Related
Does React re-render all components and sub components every time setState() is called?
If so, why? I thought the idea was that React only rendered as little as needed - when state changed.
In the following simple example, both classes render again when the text is clicked, despite the fact that the state doesn't change on subsequent clicks, as the onClick handler always sets the state to the same value:
this.setState({'test':'me'});
I would've expected that renders would only happen if state data had changed.
Here's the code of the example, as a JS Fiddle, and embedded snippet:
var TimeInChild = React.createClass({
render: function() {
var t = new Date().getTime();
return (
<p>Time in child:{t}</p>
);
}
});
var Main = React.createClass({
onTest: function() {
this.setState({'test':'me'});
},
render: function() {
var currentTime = new Date().getTime();
return (
<div onClick={this.onTest}>
<p>Time in main:{currentTime}</p>
<p>Click me to update time</p>
<TimeInChild/>
</div>
);
}
});
ReactDOM.render(<Main/>, document.body);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.0/react-dom.min.js"></script>
Does React re-render all components and sub-components every time setState is called?
By default - yes.
There is a method boolean shouldComponentUpdate(object nextProps, object nextState), each component has this method and it's responsible to determine "should component update (run render function)?" every time you change state or pass new props from parent component.
You can write your own implementation of shouldComponentUpdate method for your component, but default implementation always returns true - meaning always re-run render function.
Quote from official docs http://facebook.github.io/react/docs/component-specs.html#updating-shouldcomponentupdate
By default, shouldComponentUpdate always returns true to prevent
subtle bugs when the state is mutated in place, but if you are careful to
always treat the state as immutable and to read-only from props and state
in render() then you can override shouldComponentUpdate with an
implementation that compares the old props and state to their
replacements.
Next part of your question:
If so, why? I thought the idea was that React only rendered as little as needed - when the state changed.
There are two steps of what we may call "render":
Virtual DOM renders: when render method is called it returns a new virtual dom structure of the component. As I mentioned before, this render method is called always when you call setState(), because shouldComponentUpdate always returns true by default. So, by default, there is no optimization here in React.
Native DOM renders: React changes real DOM nodes in your browser only if they were changed in the Virtual DOM and as little as needed - this is that great React's feature which optimizes real DOM mutation and makes React fast.
No, React doesn't render everything when the state changes.
Whenever a component is dirty (its state changed), that component and its children are re-rendered. This, to some extent, is to re-render as little as possible. The only time when render isn't called is when some branch is moved to another root, where theoretically we don't need to re-render anything. In your example, TimeInChild is a child component of Main, so it also gets re-rendered when the state of Main changes.
React doesn't compare state data. When setState is called, it marks the component as dirty (which means it needs to be re-rendered). The important thing to note is that although render method of the component is called, the real DOM is only updated if the output is different from the current DOM tree (a.k.a diffing between the Virtual DOM tree and document's DOM tree). In your example, even though the state data hasn't changed, the time of last change did, making Virtual DOM different from the document's DOM, hence why the HTML is updated.
Yes. It calls the render() method every time we call setState only except when shouldComponentUpdate returns false.
Even though it's stated in many of the other answers here, the component should either:
implement shouldComponentUpdate to render only when state or properties change
switch to extending a PureComponent, which already implements a shouldComponentUpdate method internally for shallow comparisons.
Here's an example that uses shouldComponentUpdate, which works only for this simple use case and demonstration purposes. When this is used, the component no longer re-renders itself on each click, and is rendered when first displayed, and after it's been clicked once.
var TimeInChild = React.createClass({
render: function() {
var t = new Date().getTime();
return (
<p>Time in child:{t}</p>
);
}
});
var Main = React.createClass({
onTest: function() {
this.setState({'test':'me'});
},
shouldComponentUpdate: function(nextProps, nextState) {
if (this.state == null)
return true;
if (this.state.test == nextState.test)
return false;
return true;
},
render: function() {
var currentTime = new Date().getTime();
return (
<div onClick={this.onTest}>
<p>Time in main:{currentTime}</p>
<p>Click me to update time</p>
<TimeInChild/>
</div>
);
}
});
ReactDOM.render(<Main/>, document.body);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.0/react-dom.min.js"></script>
It seems that the accepted answers are no longer the case when using React hooks (with primitive values, see comments on this answer for details). You can see in this code sandbox that the class component is rerendered when the state is set to the same value, while in the function component, setting the state to the same value doesn't cause a rerender.
https://codesandbox.io/s/still-wave-wouk2?file=/src/App.js
React 18 and beyond
Starting from React 18 all state updates are automatically batched. In this way, React groups multiple state updates into a single re-render for better performance.
So when you update your state, React always try to batch these updates in a group update, causing fewer render than setState calls. The behaviour is the same when using hooks.
You can read the very long explanation in the Automatic batching for React 18 announcement.
React 17 and below
In React 17 and below, only updates inside React event handlers are batched. Updates triggered from promises, setTimeout, native event handlers, or other events are not batched in React by default.
Another reason for "lost update" can be the next:
If the static getDerivedStateFromProps is defined then it is rerun in every update process according to official documentation https://reactjs.org/docs/react-component.html#updating.
so if that state value comes from props at the beginning it is overwrite in every update.
If it is the problem then U can avoid setting the state during update, you should check the state parameter value like this
static getDerivedStateFromProps(props: TimeCorrectionProps, state: TimeCorrectionState): TimeCorrectionState {
return state ? state : {disable: false, timeCorrection: props.timeCorrection};
}
Another solution is add a initialized property to state, and set it up in the first time (if the state is initialized to non null value.)
Not All Components.
the state in component looks like the source of the waterfall of state of the whole APP.
So the change happens from where the setState called. The tree of renders then get called from there. If you've used pure component, the render will be skipped.
Regardless of the well explained answers here, there may be other reasons why you don't see the change you expect post changing the props or state:
Watch out for any event.preventDefault(); in the code where you want to re-render by a state \ props change, as it will cancel any cancelable event following this statement.
You could use setState() only after comparing the current state value and the new one and they are different.
Does React re-render all components and sub components every time setState() is called?
If so, why? I thought the idea was that React only rendered as little as needed - when state changed.
In the following simple example, both classes render again when the text is clicked, despite the fact that the state doesn't change on subsequent clicks, as the onClick handler always sets the state to the same value:
this.setState({'test':'me'});
I would've expected that renders would only happen if state data had changed.
Here's the code of the example, as a JS Fiddle, and embedded snippet:
var TimeInChild = React.createClass({
render: function() {
var t = new Date().getTime();
return (
<p>Time in child:{t}</p>
);
}
});
var Main = React.createClass({
onTest: function() {
this.setState({'test':'me'});
},
render: function() {
var currentTime = new Date().getTime();
return (
<div onClick={this.onTest}>
<p>Time in main:{currentTime}</p>
<p>Click me to update time</p>
<TimeInChild/>
</div>
);
}
});
ReactDOM.render(<Main/>, document.body);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.0/react-dom.min.js"></script>
Does React re-render all components and sub-components every time setState is called?
By default - yes.
There is a method boolean shouldComponentUpdate(object nextProps, object nextState), each component has this method and it's responsible to determine "should component update (run render function)?" every time you change state or pass new props from parent component.
You can write your own implementation of shouldComponentUpdate method for your component, but default implementation always returns true - meaning always re-run render function.
Quote from official docs http://facebook.github.io/react/docs/component-specs.html#updating-shouldcomponentupdate
By default, shouldComponentUpdate always returns true to prevent
subtle bugs when the state is mutated in place, but if you are careful to
always treat the state as immutable and to read-only from props and state
in render() then you can override shouldComponentUpdate with an
implementation that compares the old props and state to their
replacements.
Next part of your question:
If so, why? I thought the idea was that React only rendered as little as needed - when the state changed.
There are two steps of what we may call "render":
Virtual DOM renders: when render method is called it returns a new virtual dom structure of the component. As I mentioned before, this render method is called always when you call setState(), because shouldComponentUpdate always returns true by default. So, by default, there is no optimization here in React.
Native DOM renders: React changes real DOM nodes in your browser only if they were changed in the Virtual DOM and as little as needed - this is that great React's feature which optimizes real DOM mutation and makes React fast.
No, React doesn't render everything when the state changes.
Whenever a component is dirty (its state changed), that component and its children are re-rendered. This, to some extent, is to re-render as little as possible. The only time when render isn't called is when some branch is moved to another root, where theoretically we don't need to re-render anything. In your example, TimeInChild is a child component of Main, so it also gets re-rendered when the state of Main changes.
React doesn't compare state data. When setState is called, it marks the component as dirty (which means it needs to be re-rendered). The important thing to note is that although render method of the component is called, the real DOM is only updated if the output is different from the current DOM tree (a.k.a diffing between the Virtual DOM tree and document's DOM tree). In your example, even though the state data hasn't changed, the time of last change did, making Virtual DOM different from the document's DOM, hence why the HTML is updated.
Yes. It calls the render() method every time we call setState only except when shouldComponentUpdate returns false.
Even though it's stated in many of the other answers here, the component should either:
implement shouldComponentUpdate to render only when state or properties change
switch to extending a PureComponent, which already implements a shouldComponentUpdate method internally for shallow comparisons.
Here's an example that uses shouldComponentUpdate, which works only for this simple use case and demonstration purposes. When this is used, the component no longer re-renders itself on each click, and is rendered when first displayed, and after it's been clicked once.
var TimeInChild = React.createClass({
render: function() {
var t = new Date().getTime();
return (
<p>Time in child:{t}</p>
);
}
});
var Main = React.createClass({
onTest: function() {
this.setState({'test':'me'});
},
shouldComponentUpdate: function(nextProps, nextState) {
if (this.state == null)
return true;
if (this.state.test == nextState.test)
return false;
return true;
},
render: function() {
var currentTime = new Date().getTime();
return (
<div onClick={this.onTest}>
<p>Time in main:{currentTime}</p>
<p>Click me to update time</p>
<TimeInChild/>
</div>
);
}
});
ReactDOM.render(<Main/>, document.body);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.0/react-dom.min.js"></script>
It seems that the accepted answers are no longer the case when using React hooks (with primitive values, see comments on this answer for details). You can see in this code sandbox that the class component is rerendered when the state is set to the same value, while in the function component, setting the state to the same value doesn't cause a rerender.
https://codesandbox.io/s/still-wave-wouk2?file=/src/App.js
React 18 and beyond
Starting from React 18 all state updates are automatically batched. In this way, React groups multiple state updates into a single re-render for better performance.
So when you update your state, React always try to batch these updates in a group update, causing fewer render than setState calls. The behaviour is the same when using hooks.
You can read the very long explanation in the Automatic batching for React 18 announcement.
React 17 and below
In React 17 and below, only updates inside React event handlers are batched. Updates triggered from promises, setTimeout, native event handlers, or other events are not batched in React by default.
Another reason for "lost update" can be the next:
If the static getDerivedStateFromProps is defined then it is rerun in every update process according to official documentation https://reactjs.org/docs/react-component.html#updating.
so if that state value comes from props at the beginning it is overwrite in every update.
If it is the problem then U can avoid setting the state during update, you should check the state parameter value like this
static getDerivedStateFromProps(props: TimeCorrectionProps, state: TimeCorrectionState): TimeCorrectionState {
return state ? state : {disable: false, timeCorrection: props.timeCorrection};
}
Another solution is add a initialized property to state, and set it up in the first time (if the state is initialized to non null value.)
Not All Components.
the state in component looks like the source of the waterfall of state of the whole APP.
So the change happens from where the setState called. The tree of renders then get called from there. If you've used pure component, the render will be skipped.
Regardless of the well explained answers here, there may be other reasons why you don't see the change you expect post changing the props or state:
Watch out for any event.preventDefault(); in the code where you want to re-render by a state \ props change, as it will cancel any cancelable event following this statement.
You could use setState() only after comparing the current state value and the new one and they are different.
How does a component gets to know, its props are changed so that it can re-render?
Eg:
function component(props){
return <p>{this.props.childVar}</p>
}
function parentComp(){
let parentVar = 0;
setTimeout(()=>{
parentVar++;
//what happens between: after this statement is executed and till the child component is re-rendered ?
}, 1000)
return <component childVar={parentVar} />
}
One of the most important aspects of React's API is that it is declarative, and that you don't have to worry about when and how changes are being captured and handled.
Basically, each time you call render, a different tree of react elements is being made and React’s diffing algorithm will compare the old and the new tree, and will make the changes if necessary.
From a component point of view, the instance itself does not know about trees, changes and updates. After all it's just a function that returns a react element based on its paramters (props) and local state (if there is any).
You can read more about it in the Docs
In your code snippet the child component will never re-render, because what you do is just change a local variable, and child component will never know about that. So, short answer is component doesn't know is props changed.
There is two reasons for component to re-render:
this.setState was called
A parent component re-rendered
when i use react ,i find these two life cycle are too similar, componentWillReceiveProps receive nextProps as argument, shouldComponentUpdate receive nextProps and nextState as arguments, so i think shouldComponentUpdate can do the same thing and more, why react keep componentWillReceiveProps method, i wonder what's difference between these two methods
They have two different roles and execute on different situations:
shouldComponentUpdate will be called every time a prop or something in the state changes (or React think that has changed). It's function is to determine if the component should re-render by returning a boolean: true if the component should re-render (this is the default return value), or false if it shouldn't.
You can access the current and next state and props, to compare and decide if it really should re-render or not. You should not use this method for other reason.
On the other side, componentWillReceiveProps will only be called if the props changed (or seem to have changed). If only the state changes, this method won't be called.
Also, this won't decide if the component should re-render. You can use this method to, for example, change some state, or make an API call.
Check out these links:
componentWillReceiveProps: https://developmentarc.gitbooks.io/react-indepth/content/life_cycle/update/component_will_receive_props.html
shouldComponentUpdate: https://developmentarc.gitbooks.io/react-indepth/content/life_cycle/update/using_should_component_update.html
componentWillReceiveProps - as the function name states this is called whenever new props will be passed to the component and you can trigger an action depending on the new prop state
shouldComponentUpdate - is a filter function which decides if the component tree should be re-rendered. This function can serve as an additional filter where you change are happening which don't require a re-render
More info here
I'm new to React and am trying to update the state of a parent component from the child everytime an onChange action happens. The onchange action comes from an input box that when letters are typed it updates the state of searchInputVal with the value of what has been typed. I have a parent <App/> component with the following properties and states here:
updateSampleFilteredState(filteredSamples) {
this.setState({
samples: filteredSamples
});
},
getInitialState () {
return {
samples:allSamples,
searchInputVal:""
}}
I pass the properties and states down to a child component here:
updateNewSampleState(filteredSamples){
return (
this.props.updateSampleFilteredState(filteredSamples)
)
}
render() {
const filteredSamples = this.props.samples.filter(sample => {
return sample.sampleFamily.toLowerCase().indexOf(this.props.searchInputVal.toLowerCase()) !== -1;
});
this.updateNewSampleState(filteredSamples);
return <div className="samples-container-inner-styling">
{
filteredSamples.map((sample) => {
return (...
Before I added the line this.updateNewSampleState(filteredSamples); the child component would render out the filtering just fine but obviously not update the state of sample with the new filtered state. When I the line this.updateNewSampleState(filteredSamples); to execute the function in the component to set the new state I get a list of re-occuring errors that eventually make my app crash. The errors say something about an anti pattern. I'm not sure how else to update the state?
You should't be updating the state from the render function, and you are facing the reason why that's a bad way to do things. Every time you call the setState the component re-renders, so if you call it inside the render function it will be called again and so on... You should ask yourself why are you calling that function there. I guess you could just do it in the onChange function you are using for the input.
As already mentioned by #César, setting the state in the renderer doesn't make sense, since setting the state triggers a rerender of the component, so you basically get something like an infinite render loop.
Given that you are computing filteredSamples only from the props, you could compute that state in the constructor:
The constructor is the right place to initialize state.
However, note the following when deriving state from props in the constructor:
It's okay to initialize state based on props if you know what you're doing. [...]
Beware of this pattern, as it effectively "forks" the props and can lead to bugs. Instead of syncing props to state, you often want to lift the state up.
If you "fork" props by using them for state, you might also want to implement componentWillReceiveProps(nextProps) to keep the state up-to-date with them. But lifting state up is often easier and less bug-prone.