What is getSnapshotBeforeUpdate() in React? - javascript

I went through below React official site to understand about new life cycle method getSnapshotBeforeUpdate
But I couldn’t understand the advantage of this method and when exactly we should use.
Below is the example from docs and it differentiates two methods.
getSnapshotBeforeUpdate(prevProps, prevState) {
// Are we adding new items to the list?
// Capture the scroll position so we can adjust scroll later.
if (prevProps.list.length < this.props.list.length) {
const list = this.listRef.current;
return list.scrollHeight - list.scrollTop;
}
return null;
}
componentDidUpdate(prevProps, prevState, snapshot) {
// If we have a snapshot value, we've just added new items.
// Adjust scroll so these new items don't push the old ones out of view.
// (snapshot here is the value returned from getSnapshotBeforeUpdate)
if (snapshot !== null) {
const list = this.listRef.current;
list.scrollTop = list.scrollHeight - snapshot;
}
}

The two paragraphs above the example you quoted explain the need for that:
In the above example, componentWillUpdate is used to read the DOM
property. However with async rendering, there may be delays between
“render” phase lifecycles (like componentWillUpdate and render) and
“commit” phase lifecycles (like componentDidUpdate). If the user does
something like resize the window during this time, the scrollHeight
value read from componentWillUpdate will be stale.
The solution to this problem is to use the new “commit” phase
lifecycle, getSnapshotBeforeUpdate. This method gets called
immediately before mutations are made (e.g. before the DOM is
updated). It can return a value for React to pass as a parameter to
componentDidUpdate, which gets called immediately after mutations.
In other words: React 16.6 introduced a new feature called "Suspense". This feature enables async rendering - the rendering of a subtree of react components can be delayed (for example to wait for a network resource to load). It is also used internally by React to favor important DOM updates over others to increase the perceived rendering performance. This can - as one would expect - cause substantial delays between the react-side virtual DOM rendering (which triggers componentWillUpdate and render(), but may contain some async component subtree which has to be awaited) and the actual reflection to the DOM (which triggers componentDidUpdate). In older react versions before Suspense these lifecycle hooks were always called with very little delay because the rendering was completely synchronous, which justified the pattern to gather DOM information in componentWillUpdate and use it in componentDidUpdate, which is no longer the case.

The main difference is getSnapshotBeforeUpdate runs before the update, componentDidUpdate runs after.
So if there is anything you need to save before it gets overwritten, that's what getSnapshotBeforeUpdate is for. These are usually externally managed things (uncontrolled in React terms), such as the scrollPosition in your example, or when interoping with other libraries outside React (e.g. a jQuery plugin).
The main guideline is that if you are unsure, you probably don't need it. If you do, you will know it.

I made a very simple project for you to understand when we should use getSnapshotBeforeUpdate life cycle method and I used getSnapshotBeforeUpdate to store user scroll position and used that in componentDidUpdate
github repository
https://github.com/mahdimehrabi/getSnapShot-sample
demo
https://mahdimehrabi.github.io/js/snapshot/

Well, actually getSnapshotBeforeUpdate() runs after the update.
Consider this which kinda explains everything:
class Demo extends React.Component {
constructor(props) {
super(props);
this.state = {x:1};
console.log(1);
}
componentDidMount() {
this.setState({x:2});
console.log(3);
}
shouldComponentUpdate() {
console.log(4);
return true;
}
getSnapshotBeforeUpdate(prevProps, prevState){
console.log(5,prevState.x,this.state.x);
return 999;
}
componentDidUpdate(prevProps, prevState, snapshot) {
console.log(6,snapshot);
}
componentWillUnmount() {
console.log(7);
}
render() {
console.log(2);
return null;
}
}
ReactDOM.render(
<Demo />,
document.querySelector('div')
);
ReactDOM.unmountComponentAtNode(document.querySelector('div'));
The output is:
1
2
3
4
2
5 1 2
6 999
7

Related

Entire NextPage from NextJs is executed after Button Change. It should only executed the change. What am I doing wrong? [duplicate]

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.

Measuring a DOM node

I know that calling setState() immediately in componentDidMount() is a performance issue and it is better to use the constructor in some cases.
But in the last sentence of the React documentation it talks about a USE CASE that states that calling setState() immediately in componentDidMount() if it is VIABLE, what does THAT USE CASE mean.
Documentation React:
You may call setState() immediately in componentDidMount(). It will
trigger an extra rendering, but it will happen before the browser
updates the screen. This guarantees that even though the render() will
be called twice in this case, the user won’t see the intermediate
state. Use this pattern with caution because it often causes
performance issues. In most cases, you should be able to assign the
initial state in the constructor() instead. It can, however, be
necessary for cases like modals and tooltips when you need to measure
a DOM node before rendering something that depends on its size or
position.
I would like an simple example (with code), PLEASE, because I have not been able to see it in words alone
Sometimes you might need access to the DOM elements managed by React—for example, to focus a node, scroll to it, or measure its size and position. There is no built-in way to do those things in React, so you will need a ref to the DOM node. During the first render, the DOM nodes have not yet been created, so ref.current will be null. And during the rendering of updates, the DOM nodes haven’t been updated yet. So it’s too early to read them. This is why sometimes you have to wait to read ref and set state in componentDidMount, or in useEffect for functionnal components
Example to get the height of an element:
class DivSize extends Component {
constructor(props) {
super(props)
this.state = {
height: 0
}
}
componentDidMount() {
const height = this.divElement.clientHeight;
this.setState({ height });
}
render() {
return (
<div
ref={ (divElement) => { this.divElement = divElement } }
>
Size: <b>{this.state.height}px</b> but it should be 18px after the render
</div>
)
}
}

Measuring react components mount times

I'm trying to find a way to measure the time certain components take to mount, taking into consideration than the library for measuring is asynchronous (firebase-performance) to be specific.
I need to find out how long a page consisting of multiple asynchronously mounted components takes to render. I am not sure, how I should go about tracking the time between the time component is invoked (function) and the time it takes to mount (render).
I'm slightly confused by the life-cycle methods, as componentWillMount is considered deprecated. Basically, my understanding would be, that in order to track the time component takes to render would be the following.
class Example extends Component<Props> {
async componentDidMount() {
// let's just say this takes 3 seconds as an external API call
await exampleCall()
}
render() {
return <h1>Test</h1>
}
}
And in order to measure the performance of this component in a easily reproducable way, I wanted to construct a wrapper for the component
import perf from '#react-native-firebase/perf'
const withPerformance = (PassedComponent) => {
class Tracker extends Component<Props> {
constructor(props) {
super(props)
console.log('constructor fired')
this.trace = null
}
async componentWillMount() {
const trace = await perf.stratTrace('perf_test')
console.log('Started perf tracking')
this.trace = trace
}
async componentDidMount() {
if (this.trace) {
console.log('Stopped tracking perf')
await this.trace.stop()
} else {
console.log('Mounted, but tracking did not instantiate')
}
}
render() {
return <PassedComponent {...this.props} />
}
}
return Tracker
}
So in order for my perf tracking needs, I could just wrap my existing components with the following wrapper
// last line of Example.js:
export default withPerformance(Example)
This however results, when opening the remote debugger in my simulator with very confusingly:
constructor fired [constructor]
Mounted, but tracking did not instantiate [componentDidMount]
Started perf tracking [componentWillMount]
And my firebase console is empty with no custom traces.
This is confusing and wrong for multiple reasons, but the worst culprit is obviously the breaking of the flow of the lifecycle methods, which should be as follows:
But in my case, it seems to be constructor -> CDM -> CWM
This seems to seemingly break the component lifecycle as componentWillMount somehow fires after componentDidMount (albeit this might be due to the asynchronous nature), which is not ideal to begin with.
componentWillMount is a deprecated lifecycle method to begin with, but there seems to be no replacement for it introduced where I could begin any asynchronous subscriptions before the actual DOM nodes are loaded.
I am forced to use asynchronity in the lifecycle methods, which is not ideal to begin with.
As of note, I am aware of the Profiler introduced in react, but I need this to be able to work in production as well, which right now is not recommended with the Profiler.
Any idea how I should go about doing this?
I did experiment with manual tracking with performance.now() which does work, but it's a client requirement (not in an architectural, but actual client sense) does want the integration to work with the firebase performance tracking.

What is determining the order in which these components' 'mount' functions execute?

In my code, app is the highest (functional) component. It renders piggybank (which is a class component) which renders piggychild (which is a functional component).
Each component 'console.logs' the name of itself (in the render method for class-component; simply in the function for a functional component) and has a 'mount' function (for the class-component, this means a componentDidMount method; for functional component, this means a useEffect hook whose callback's 2nd parameter is an empty array) which logs 'mount' to the console.
As you can see in the picture, PiggyBank's mount fires first, then PiggyChild's, then App's.
Is there a rule in React that governs the order in which components' 'mount' functions occur?
Or is it enough to just know that mount functions occur after all components are rendered?
useEffect has a different timing than componentDidMount. The hook that's closest to CDM is actually useLayoutEffect.
Here's a bit from ReactTraining's blog on useEffect:
They run at different times
First, let's talk about the timing of each. componentDidMount runs
after the component mounts. As the docs say, if you set state
immediately (synchronously) then React knows how to trigger an extra
render and use the second render's response as the initial UI so the
user doesn't see a flicker. Imagine you need to read the width of a
DOM element with componentDidMount and want to update state to reflect
something about the width. Imagine this sequence of events:
Component renders for the first time.
The return value of render() is used to mount new DOM.
componentDidMount fires and sets state immediately (not in an async
callback)
The state change means render() is called again and returns new JSX
which replaces the previous render.
The browser only shows the second render to avoid flicker.
It's nice that this is how it works for when we need it. But most the
time we don't need this pre-optimized approach because we're doing
asynchronous network calls and then setting state after the paint to
the screen.
componentDidMount and useEffect run after the mount. However useEffect
runs after the paint has been committed to the screen as opposed to
before. This means you would get a flicker if you needed to read from
the DOM, then synchronously set state to make new UI.
How do get the old behavior back when we need it?
useLayoutEffect was designed to have the same timing as
componentDidMount. So useLayoutEffect(fn, []) is a much closer match
to componentDidMount() than useEffect(fn, []) -- at least from a
timing standpoint.
Does that mean we should be using useLayoutEffect instead?
Probably not.
If you do want to avoid that flicker by synchronously setting state,
then use useLayoutEffect. But since those are rare cases, you'll want
to use useEffect most of the time.
I've added an example which has both Layout Effects and normal Effects in the scenario you described:
The results of running this are as follows. The main thing to note with this is that The Layout effects happen in a sensible order with the componentDidMount lifecycle hook, whereas the effects happen later.
App
PiggyBank
PiggyChild
PiggyChild LayoutEffect
PiggyBank Mount
App LayoutEffect
PiggyChild Effect
App Effect
const {useEffect, useLayoutEffect} = React;
function App(){
console.log('App');
useLayoutEffect(()=>console.log('App LayoutEffect'),[]);
useEffect(()=>console.log('App Effect'),[]);
return <PiggyBank/>;
}
class PiggyBank extends React.Component{
componentDidMount(){
console.log('PiggyBank Mount');
}
render(){
console.log('PiggyBank');
return <PiggyChild/>
}
}
function PiggyChild(){
console.log('PiggyChild');
useLayoutEffect(()=>console.log('PiggyChild LayoutEffect'),[]);
useEffect(()=>console.log('PiggyChild Effect'),[]);
return <div/>;
}
ReactDOM.render(<App/>,document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
<div id="root"/>
Without the LayoutEffects, the order will be:
The console.logs in the render functions, in order from parent to child, since part of rendering each component is rendering the children
Then the componentDidMount runs immediately after it finishes mounting. If there are multiple components with componentDidMounts or useLayoutEffects, these would be called in order from from child to parent as they finish mounting, but before the paint is committed (as mentioned above).
The useEffects run in order from child to parent as they finished mounting in that order, but they will always run after the componentDidMounts and useLayoutEffects due to the timing mentioned above.
const {useEffect} = React;
function App(){
console.log('App');
// useLayoutEffect(()=>console.log('App LayoutEffect'),[]);
useEffect(()=>console.log('App Effect'),[]);
return <PiggyBank/>;
}
class PiggyBank extends React.Component{
componentDidMount(){
console.log('PiggyBank Mount');
}
render(){
console.log('PiggyBank');
return <PiggyChild/>
}
}
function PiggyChild(){
console.log('PiggyChild');
// useLayoutEffect(()=>console.log('PiggyChild LayoutEffect'),[]);
useEffect(()=>console.log('PiggyChild Effect'),[]);
return <div/>;
}
ReactDOM.render(<App/>,document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
<div id="root"/>
Actually it makes absolute sense, and order of useEffect in hierarchy is the same as in componentDidMount.
The thing is that componentDidMount fires when all children mounted (so you would see first child event, and only then parent one) - so same order as you see.
For more details about order of componentDidMount you could see here - Order of componentDidMount in React components hierarchy

How to efficiently update state/component in React on state change [duplicate]

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.

Categories

Resources