I'm learning react, and I'm stuck with not updating list components.
The component shows all of the list elements that I add manually, but not rendering any changes.
I searched a lot for solutions.
All of my change handlers are binded, the setState inside handleSubmit should update ClockRow...
My App.js:
import React, { Component } from 'react';
import Clock from './Clock';
import ClockRow from './ClockRow';
class App extends Component {
constructor(props) {
super(props);
this.state = {items: [], tle: 'Teszt', ival: 200};
this.handleChangeTitle = this.handleChangeTitle.bind(this);
this.handleChangeInterval = this.handleChangeInterval.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChangeTitle(event) {
this.setState({tle: event.target.value});
}
handleChangeInterval(event) {
this.setState({ival: event.target.value});
}
handleSubmit(event) {
if(this.state.tle.length > 0 && this.state.ival > 9){
this.setState({items: [...this.state.items, <Clock interval={this.state.ival} title={this.state.tle} />]});
}
event.preventDefault();
}
render(){
return (
<div>
<div className="row">
<h1 className="col text-center">Hello, React!</h1>
</div>
<div className="row">
<form onSubmit={this.handleSubmit}>
<label>
Title: <input type="text" name="tle" value={this.state.tle} onChange={this.handleChangeTitle} />
</label>
<label>
Interval: <input type="number" name="ival" value={this.state.ival} onChange={this.handleChangeInterval} />
</label>
<input type="submit" value="Add" />
</form>
</div>
<ClockRow clockItems={this.state.items} />
</div>
);
}
}
export default App;
My ClockRow.js:
import React, { Component } from 'react';
class ClockRow extends Component{
constructor(props){
super(props);
this.state = {clocks: props.clockItems.map((x, i) => <div className="col" key={i}>{x}</div>) }
}
render(){
return(<div className="row">{this.state.clocks}</div>
)};
}
export default ClockRow;
My Clock.js:
import React, { Component } from 'react';
import {Card, CardTitle, CardBody, CardFooter} from 'reactstrap';
class Clock extends Component {
constructor(props){
super(props);
this.state = {counter: 0, interval: parseInt(props.interval), title: props.title};
}
componentDidMount() {
this.timerID = setInterval(() => this.tick(), this.state.interval);
}
componentWillUnmount() {
clearInterval(this.timerID);
}
tick() {
this.setState((state) => ({
counter: state.counter + 1
}));
}
render() {
return (
<Card>
<CardTitle>{this.state.title}</CardTitle>
<CardBody>{this.state.counter}</CardBody>
<CardFooter>{this.state.interval}</CardFooter>
</Card>
);
}
}
export default Clock;
CodeSandbox:
https://codesandbox.io/s/zxlzzv05n3
ClockRow.js is surplus
Clock.js is not changed
App.js is changed, and "React styled":
import React, { Component } from "react";
import Clock from "./Clock";
class App extends Component {
constructor(props) {
super(props);
this.state = { items: [], inputTle: "Teszt", inputIval: 200 };
}
handleChangeTitle = event => {
this.setState({ inputTle: event.target.value });
};
handleChangeInterval = event => {
this.setState({ inputIval: event.target.value });
};
handleSubmit = event => {
console.log(this.state);
if (this.state.inputTle.length > 0 && this.state.inputIval > 9) {
this.setState(prevState => {
return {
items: [
...prevState.items,
{
title: this.state.inputTle,
interval: this.state.inputIval
}
]
};
});
}
event.preventDefault();
};
render() {
return (
<div>
<div className="row">
<h1 className="col text-center">Hello, React!</h1>
</div>
<div className="row">
<form onSubmit={this.handleSubmit}>
<label>
Title:{" "}
<input
type="text"
name="tle"
value={this.state.inputTle}
onChange={this.handleChangeTitle}
/>
</label>
<label>
Interval:{" "}
<input
type="number"
name="ival"
value={this.state.inputIval}
onChange={this.handleChangeInterval}
/>
</label>
<input type="submit" value="Add" />
</form>
</div>
<div className="row">
{this.state.items.map((item, index) => (
<div className="col" key={index}>
<Clock {...item} />
</div>
))}
</div>
</div>
);
}
}
export default App;
Related
Trying to learn React/RoR and in this simple test app I have a 'searchapp' react app. That sets a default for the language radioboxes.
import React from 'react'
import ReactDOM from 'react-dom'
import axios from "axios";
import SearchForm from "./searchForm";
class SearchApp extends React.Component {
constructor(props) {
super(props);
this.state = {
searchStrings: [],
subjectName: "",
language: 'English',
region: ""
};
this.getSearchStrings = this.getSearchStrings.bind(this);
}
componentDidMount() {
this.getSearchStrings();
}
handleClickLang = changeEvent => {
this.setState({
language: changeEvent.target.value
});
};
getSearchStrings() {
axios
.get("/api/v1/search_strings")
.then(response => {
const searchStrings = response.data;
this.setState({searchStrings});
})
.catch(error => {
console.log(error);
});
}
render() {
return (
<>
<SearchForm />
</>
);
}
}
and then in the searchForm component I use that state to set and switch between two radio buttons.
class SearchForm extends React.Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
this.subjRef = React.createRef();
//this.handleClickLang = this.handleClickLang.bind(this);
}
componentDidMount() {
this.setState({
language: 'English'
});
}
handleSubmit(e) {
e.preventDefault();
window.alert("sometext");
}
render() {
return (
<form onSubmit={this.handleSubmit} className="my-3">
<div className="form-row">
<div className="form-group col-md-8">
<p>Choose language</p>
</div>
<div className="form-row">
<div className="form-check">
<label>
<input
type="radio"
name="react-tips"
value="English"
checked={this.state.language === 'English'}
onChange={this.handleClickLang}
className="form-check-input"
/>
English
</label>
</div>
<div className="form-check">
<label>
<input
type="radio"
name="react-tips"
value="Russian"
checked={this.state.language === 'Russian'}
onChange={this.handleClickLang}
className="form-check-input"
/>
Russian
</label>
</div>
However when I run this I get the following error:
Uncaught TypeError: Cannot read properties of null (reading 'language')
I thought this was erroring because it cannot find a default language, however I initialised language to 'English' in the constructor for the SearchApp.
Is this me not understanding React state enough? Any help much appreciated.
In the componentDidMount i feel the language is getting to null, you can try the following:
Trying to learn React/RoR and in this simple test app I have a 'searchapp' react app. That sets a default for the language radioboxes.
import React from 'react'
import ReactDOM from 'react-dom'
import axios from "axios";
import SearchForm from "./searchForm";
class SearchApp extends React.Component {
constructor(props) {
super(props);
this.state = {
searchStrings: [],
subjectName: "",
language: 'English',
region: ""
};
this.getSearchStrings = this.getSearchStrings.bind(this);
}
componentDidMount() {
this.getSearchStrings();
}
handleClickLang = changeEvent => {
this.setState({
language: changeEvent.target.value
});
};
getSearchStrings() {
axios
.get("/api/v1/search_strings")
.then(response => {
const searchStrings = response.data;
this.setState({searchStrings,language: 'English'});
})
.catch(error => {
console.log(error);
});
}
render() {
return (
<>
<SearchForm language={this.state.language}/>
</>
);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
And in the SearchForm component pass the language via props
class SearchForm extends React.Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
this.subjRef = React.createRef();
//this.handleClickLang = this.handleClickLang.bind(this);
}
handleSubmit(e) {
e.preventDefault();
window.alert("sometext");
}
render() {
return (
<form onSubmit={this.handleSubmit} className="my-3">
<div className="form-row">
<div className="form-group col-md-8">
<p>Choose language</p>
</div>
<div className="form-row">
<div className="form-check">
<label>
<input
type="radio"
name="react-tips"
value="English"
checked={this.props.language === 'English'}
onChange={this.handleClickLang}
className="form-check-input"
/>
English
</label>
</div>
<div className="form-check">
<label>
<input
type="radio"
name="react-tips"
value="Russian"
checked={this.props.language === 'Russian'}
onChange={this.handleClickLang}
className="form-check-input"
/>
Russian
</label>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
But there are several more things:
Why are you also having language state in searchForm, you can have it in Search component and pass it via props
Yo are not initializing any state in the constructor in your SearchForm component
Adding a followup here for future reference.
As suggested by #Thor84no the problem was not adding state = {} to intialise state in the sub component.
Im already learning about to fetch data from REST API with react, i have to components (form for submit and a card for get data) both summon from parent component (App), and is working, so i got to push new todo to db and get the news values on my card component, but instead only render cards components, render the all App (incluyed the form component), what am i doing wrong guys?
This is the parent Component
import React, { Component } from 'react';
import './App.css';
import SampleCard from './components/SampleCard';
import Form from './components/Form';
class App extends Component {
constructor(props) {
super(props);
this.state = {
data: []
}
}
componentDidMount() {
this.getTasks()
}
getTasks =_=> {
fetch('http://localhost:4000/users')
.then(response => response.json())
.then(data => this.setState({ data: data.data }))
.catch(err => console.log(err))
}
render() {
return (
<div>
<form onSubmit={this.getTasks}>
<Form />
</form>
{this.state.data.map((row, i) => (
<div key={i}>
<SampleCard row={row} />
</div>
))}
</div>
)
}
}
export default App;
This, the form component
import React, { Component } from "react";
class Form extends Component {
constructor(props) {
super(props);
this.state = {
tasks: {
task: '',
status: ''
}
}
}
addTask = _ => {
const { tasks } = this.state
fetch(`http://localhost:4000/users/add?task=${tasks.task}&status=${tasks.status}`)
.catch( err => console.log(err))
}
render() {
const { tasks } = this.state
return (
<div className="Form container mt-3">
<div className="input-group mb-3">
<div className="input-group-prepend">
<span className="input-group-text" id="basic-addon1">
Define Task!
</span>
</div>
<input
type="text"
value={tasks.task}
onChange={e => this.setState({ tasks: { ...tasks, task: e.target.value } })}
className="form-control"
placeholder="Task"
aria-label="Task"
aria-describedby="basic-addon1"
/>
</div>
<div className="input-group mb-3">
<div className="input-group-prepend">
<span className="input-group-text" id="basic-addon1">
Define Status!
</span>
</div>
<input
type="text"
value={tasks.status}
onChange={e => this.setState({ tasks: { ...tasks, status: e.target.value } })}
className="form-control"
placeholder="Status"
aria-label="Status"
aria-describedby="basic-addon1"
/>
</div>
<button
type="Submit"
className="btn btn-outline-success d-flex mr-auto"
onClick={this.addTask}
>
Add
</button>
</div>
);
}
}
export default Form;
and this the card component
import React, { Component } from "react";
export default class SampleCard extends Component {
render() {
return (
<div className="container pt-5">
<div className="col-xs-12">
<div className="card">
<div className="card-header">
<h5 className="card-title">{this.props.row.task}</h5>
</div>
<div className="card-body">
<h4 className="card-title">{this.props.row.created_at}</h4>
{this.props.row.status === 1 ? (
<h3 className="card-title">Pending</h3>
) : (
<h3 className="card-title">Completed</h3>
)}
</div>
</div>
</div>
</div>
);
}
}
You're not preventing default submit behavior. Do it like this
getTasks = (e) => {
e.preventDefault();
fetch('http://localhost:4000/users')
.then(response => response.json())
.then(data => this.setState({ data: data.data }))
.catch(err => console.log(err))
}
Whenever using submit with a form, use e.preventDefault() it prevents refreshing.
When I insert any text in input field, screen disappears, I am new to UI, learning ReactJs, help me out please.
import React from 'react';
class InputChange extends React.Component{
constructor(props){
super(props)
this.state={
input:''
}
}
updateState = (text) => {
this.setState({input: text});
}
render(){
return(
<div>
<div>Input:{this.state.input}</div>
<div>
<input type="text" value={this.state.input} onChange={this.updateState} />
</div>
</div>`
);
}
}
export default InputChange;
It's event.target.value...:
class InputChange extends React.Component {
state = { input: '' };
updateState = event => {
this.setState({ input: event.target.value });
};
render() {
return (
<div>
<div>Input:{this.state.input}</div>
<div>
<input
type="text"
value={this.state.input}
onChange={this.updateState}
/>
</div>
</div>
);
}
}
export default InputChange;
More info in the docs: https://reactjs.org/docs/forms.html
I'm working whith one representational component (ProjectFormUpdate) and his container (ProjectFormUpdateContainer). From the container, i send an document object Project and a flag isLoading. But in a Constructor() of ProjectFormUpdate, the flag is false... the state is never seted.
The representational componente
import React, { Component} from 'react';
import ReactDOM from 'react-dom';
import { Projects } from '/imports/api/projects.js';
import PropTypes from 'prop-types'; // ES6
import { withTracker } from 'meteor/react-meteor-data';
export default class ProjectFormUpdate extends Component {
handleUpdate(event) {
event.preventDefault();
console.log("se modificó el estadoooo")
this.setState({
codigo: ReactDOM.findDOMNode(this.refs.codigoInput).value.trim(),
nombre: ReactDOM.findDOMNode(this.refs.nombreInput).value.trim()
});
}
handleSubmit(event){
this.setState({
codigo: ReactDOM.findDOMNode(this.refs.codigoInput).value.trim(),
nombre: ReactDOM.findDOMNode(this.refs.nombreInput).value.trim()
});
}
constructor(props) {
super(props);
if (!props.isLoading){
this.state = {
codigo: props.oneProject.codigo,
nombre: props.oneProject.nombre}
}
else{
this.state = {
codigo: 'dd',
nombre: 'ff'}
}
}
render() {
const { oneProject, isLoading } = this.props;
if (!isLoading){
this.setState = {
codigo: this.props.oneProject.codigo,
nombre: this.props.oneProject.nombre}
return (
<div className="col-xs-11">
<div className="box box-solid">
<form className="form" onSubmit={this.handleSubmit.bind(this)} >
<div className="box-body">
<div className="row">
<div className="col-xs-2">
<input
className = "form-control input-sm"
type="text"
ref="codigoInput"
placeholder="Código del Proyecto"
value = {this.state.codigo}//this.state.codigo}
onChange = {this.handleUpdate.bind(this)}
/>
</div>
<div className="col-xs-6">
<input
className = "form-control input-sm"
type="text"
ref="nombreInput"
placeholder="Título"
value = {this.state.nombre }
onChange = {this.handleUpdate.bind(this)}
/>
</div>
</div>
</div>
<div className="box-footer">
<button type="submit" className="btn btn-sm btn-primary btn-flat">Guardar</button>
</div>
</form>
</div>
</div>
);
}
else {return (<div></div>);}
}}
ProjectFormUpdate.propTypes = {
// This component gets the task to display through a React prop.
// We can use propTypes to indicate it is required
oneProject: React.PropTypes.object,
isLoading: React.PropTypes.bool,
};
The Container
import { Meteor } from 'meteor/meteor';
import { withTracker } from 'meteor/react-meteor-data';
import { Projects } from '/imports/api/projects.js';
import ProjectFormUpdate from './ProjectFormUpdate.jsx';
export default ProjectFormUpdateContainer = withTracker(({ key1 }) => {
const sub = Meteor.subscribe('projects');
var oneProject = Projects.findOne(key1);
var isLoading = !sub.ready();
return {
oneProject,
isLoading,
};
})(ProjectFormUpdate);
So... if i can't set the state, i can't set the form's values in a controled way. Any suggestion?
In order to set your components state outside of the constructor() function: you must call this.setState(). this.setState() will set it's first argument as the new state and subsequently call your component's render function.
Your if (!isLoading) statement is very dangerous. Assuming !isLoading == true: your render function will infinitely fire this.setState(), thereby locking your browser.
Your constructor function appears correct, as is. I would allow it to set the initial application state and handle the rest from within the render() function. Alternatively, you could set your initial state within the componentWillMount() or componentDidMount() functions found here.
Within your render() function, I would omit the if (!isLoading) part and instead try returning a loading component if (isLoading == true).
You can also apply the following logic directly to your <input/> elements to set your component's state with finesse:
<input value={this.state.key} onChange={(event) => this.setState({key: event.target.value})}/>
I've revised your ProjectFormUpdate component as follows:
import React, { Component} from 'react';
import ReactDOM from 'react-dom';
import { Projects } from '/imports/api/projects.js';
import PropTypes from 'prop-types'; // ES6
import { withTracker } from 'meteor/react-meteor-data';
export default class ProjectFormUpdate extends Component {
handleSubmit(event){
event.preventDefault()
console.log()
}
constructor(props) {
super(props);
if (!props.isLoading) {
this.state = {
codigo: props.oneProject.codigo,
nombre: props.oneProject.nombre
}
}
else {
this.state = {
codigo: '',
nombre: ''
}
}
}
render() {
const { oneProject, isLoading } = this.props;
if (isLoading) {
return (
<div>isLoading == true</div>
)
}
return (
<div className="col-xs-11">
<div className="box box-solid">
<form className="form" onSubmit={this.handleSubmit.bind(this)} >
<div className="box-body">
<div className="row">
{/* Codigo. */}
<div className="col-xs-2">
<input className = "form-control input-sm" type="text" ref="codigoInput" placeholder="Código del Proyecto" value={this.state.codigo} onChange={(event) => this.setState({codigo: event.target.value})} />
</div>
{/* Nombre. */}
<div className="col-xs-6">
<input className = "form-control input-sm" type="text" ref="nombreInput" placeholder="Título" value={this.state.nombre} onChange={(event) => this.setState({nombre: event.target.value}))} />
</div>
</div>
</div>
<div className="box-footer">
<button type="submit" className="btn btn-sm btn-primary btn-flat">Guardar</button>
</div>
</form>
</div>
</div>
)
}
ProjectFormUpdate.propTypes = {
oneProject: React.PropTypes.object,
isLoading: React.PropTypes.bool,
};
I am new to react.In my application I have to perform crud action on inputset(contains one selectbox and textarea) within form.Form loads with one inputset with default values.
Actions
Onchange of inputset text it should update state if not it should
store with default values.
OnAdd it should check previous element has not empty description.
Paricular inputSet should be removed and on clearing description
also it should remove that inputSet
Image:
Code:
Item
import React from 'react';
import { Input, Button, Glyphicon } from 'react-bootstrap';
export default class TextBoxesSet extends React.Component {
constructor(props) {
super(props);
}
_onRemoveName = () => {
console.log('remove');
}
static getPropsFromStores() {
return {language: 'en', description: ''};
}
render() {
return (
<div >
<div className="">
<Input type="select" placeholder="select" wrapperClassName="col-xs-4"
value={this.props.language} onChange={this.handleChange.bind(this, 'language')} >
<option value="en">en</option>
<option value="de">de</option>
</Input>
</div>
<div className="col-md-7">
<Input type="textarea" wrapperClassName="col-xs-12" value={this.props.description}
onChange={this.handleChange.bind(this, 'description')} />
</div>
<div className="col-md-1">
<Button bsSize="small"><Glyphicon glyph="remove" onClick={this._onRemoveName} /></Button>
</div>
</div>
);
}
handleChange(name, e) {
const obj = {};
obj[name] = e.target.value;
this.setState(obj);
if (this.state.language !== undefined && this.state.description !== undefined) {
this.props.handleChange('name', this.state);
}
}
}
TextBoxesSet.propTypes = {
language: React.PropTypes.string,
description: React.PropTypes.string,
handleChange: React.PropTypes.func
};
List
import React from 'react';
import { Button, Glyphicon } from 'react-bootstrap';
// import TextBoxStore from 'stores/textBoxStore';
import TextBoxesSet from './descriptionTextBoxes';
export default class TextBoxesSetList extends React.Component {
constructor(props) {
super(props);
}
_onAddName = (label) => {
if (this.state) {
this.state[label].length++;
React.render(<TextBoxesSet labelName="name" language="de" handleChange={this.handleTextBoxSetChange}/>, document.getElementById('another'));
}
}
_onRemoveName = () => {
console.log('remove');
}
render() {
return (
<div >
<ul >
<TextBoxesSet label={this.props.labelName} handleChange={this.props.handleChange}/>
</ul>
<div className="col-md-1">
<Button bsSize="small"><Glyphicon glyph="plus" onClick={this._onAddName} /></Button>
</div>
</div>
);
}
}
TextBoxesSetList.propTypes = {
newItem: React.PropTypes.string,
list: React.PropTypes.array,
labelName: React.PropTypes.string,
handleChange: React.PropTypes.func
};
Form
import React from 'react';
import { Input, Button, Glyphicon, ButtonToolbar } from 'react-bootstrap';
import AttributeSectionStore from 'stores/attributeSection/AttributeSectionStore';
import TextBoxesSetList from '../TextBoxesList';
import styles from 'scss/_common';
export default class Name extends React.Component {
constructor(props) {
super(props);
this.handleTextBoxSetChange = this.handleTextBoxSetChange.bind(this);
}
_onCreate = () => {
console.log('___________', this.state);
}
static getPropsFromStores() {
return AttributeSectionStore.getState();
}
render() {
return (
<div className="container">
<div className={styles.mainheader}>
<h2 >New Form</h2>
</div>
<div className="col-md-9">
<form className="form-horizontal">
<div className="row">
<div className="col-xs-2">
<label className="">Name</label>
</div>
<div className="col-md-6">
<TextBoxesSetList labelName="name" handleChange={this.handleTextBoxSetChange}/>
</div>
</div>
</form>
</div>
</div>
);
}
handleChange(name, e) {
const change = {};
change[name] = e.target.value;
this.setState(change);
}
handleTextBoxSetChange(label, obj) {
const change = {};
if (this.state[label] === undefined) {
console.log('--------------------');
change[label] = [];
change[label].push(obj);
}
this.setState(change);
}
}
Name.propTypes = {
name: React.PropTypes.arrayOf(React.PropTypes.object)
};
Please help me in solving?