How To Update (re-render) The Child Components In React When The Parent's State Change?
Okay, I already know one way to do this. However, I am asking this in case I am reinventing the wheel since I am very new to React. I was under the impression that if a parent component passes her state to the child components via props than upon updating the parent's state, the child will re-render if needed. But this does not seem to be the case. I set up this example,
class Child extends Component {
constructor(props) {
super(props);
this.state = {
number: props.number,
};
}
updateNumber(n) {
this.setState({number: n});
}
render() {
return (<h1>{this.state.number}</h1>);
}
}
class Parent extends Component {
constructor(props) {
super(props);
this.state = {
number: -1,
};
this.child = React.createRef();
setInterval(this.updateState.bind(this), 1000);
}
updateState() {
console.log(this.state);
this.setState({
number: Math.floor((Math.random() * 10) + 1),
});
// this.child.current.updateNumber(this.state.number);
}
render() {
return (
<div>
<Child ref={this.child} number={this.state.number}/>
</div>
);
}
}
In this example, unless I explicitly define a reference and use it to call the child's update function (the commented part), child is not re-rendered each time the parent's state is updated. So is that it? Are you suppose to manually update the state of your children (heh) or should they automatically update (and thus re-render) if their parent's state is passed to them as props.
Answer
It is because your Child component is using its own state as well. Always ask yourself if state
is necessary, its a common mistake for React beginner.
Hope you can understand it more by looking at this example. Instead of calling setInterval
in your constructor function, I will recommend you to call it in componentDidMount
and to clearInterval
in your componentWillUnmount
.
// Since you are not using state, you can use functional component for your Child component
const Child = ({ number }) => <h1>{number}</h1>;
class Parent extends React.Component {
constructor(props) {
super(props);
this.timer = null;
this.state = { number: 0 };
}
componentDidMount() {
// setInterval after component did mount
this.timer = setInterval(this.incrementNumber, 1000);
}
componentWillUnmount() {
// clearInterval when component is going to unmount
if (this.timer) {
clearInterval(this.timer);
}
}
incrementNumber = () => {
// setState function callback to ensure state received will be latest state
this.setState(prevState => ({ number: prevState.number + 1 }));
}
render() {
const { number } = this.state;
return (
<div>
<Child number={number} />
</div>
);
}
}
Related Questions
- → How to update data attribute on Ajax complete
- → October CMS - Radio Button Ajax Click Twice in a Row Causes Content to disappear
- → Octobercms Component Unique id (Twig & Javascript)
- → Passing a JS var from AJAX response to Twig
- → Laravel {!! Form::open() !!} doesn't work within AngularJS
- → DropzoneJS & Laravel - Output form validation errors
- → Import statement and Babel
- → Uncaught TypeError: Cannot read property '__SECRET_DOM_DO_NOT_USE_OR_YOU_WILL_BE_FIRED' of undefined
- → React-router: Passing props to children
- → ListView.DataSource looping data for React Native
- → Can't test submit handler in React component
- → React + Flux - How to avoid global variable
- → Webpack, React & Babel, not rendering DOM