After reading here about immutability, I am trying to understand how react is working. I am trying to understand with the help of following 3 components, however its not making sense.
const bla = {a: 1};
class Test extends React.Component {
constructor(props) {
super(props);
this.state = {
a: 1,
};
this.onClick = () => this.setState(prevState => ({
a: prevState.a + 1
}));
}
render() {
console.log('Render default');
return <div id="test" onClick = {
this.onClick
} > DOM Updating: {
this.state.a
} < /div>;
}
}
class Test1 extends React.Component {
constructor(props) {
super(props);
this.state = {
a: 1,
};
this.onClick = () => this.setState(prevState => ({
a: 1
}));
}
render() {
console.log('Render 1');
return <div id="test1" onClick = {
this.onClick
} > DOM not updating: {
this.state.a
} < /div>;
}
}
class Test2 extends React.Component {
constructor(props) {
super(props);
this.state = bla;
this.onClick = () => {
const mutating = this.state;
mutating.a = this.state.a + 1;
this.setState(mutating);
};
}
render() {
console.log('Render 2');
return <div id="test2" onClick = {
this.onClick
} > DOM updating with mutation: {
this.state.a
} < /div>;
}
}
ReactDOM.render( < div > < Test / > < Test1 / > < Test2 / > < /div>, document.getElementById('root'));
<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>
<div id="root"></div>
If I inspect div id="test1" it is updating in Chrome dev tool on each click. Want to understand below points:
In fact, React.js does not need to have knowledge about what exactly changed. All it needs to know is whether the state changed at all or not.
1.) In the console output, you simply see Render 1
, because you invoke setState
with the static value 1
. But in fact, each time you invoke setState
with the click, React will set a new (in the sence of new object reference) state for the component, and a new render cycle is triggered.
setState() will always lead to a re-render unless shouldComponentUpdate() returns false. Link
2.) See answer 1. In addition, you have a DOM change, because state changes are merged.
When you call setState(), React merges the object you provide into the current state.
In your Test2 click handler code, mutating will be merged into the current state. It is the same object, but important is, that all its properties (here a
property) will be spread into the state, resulting in a new state object.
const mutating = this.state;
mutating.a = this.state.a + 1;
this.setState(mutating);
3.) Let's say you have a Parent
component containing all your child components. If you change props
or state
of Parent
, all children will be rerendered by React, unless their shouldComponentUpdate
hook returns false or they are PureComponent
s, whose props or state did not change.
setState() enqueues changes to the component state and tells React that this component and its children need to be re-rendered with the updated state. Link
Rerender means, that for each child, React compares the previous and the current version in a Reconciliation step. It only leads to a DOM update, if the child has really changed, otherwise nothing happens. See here for a nice visualization.