getDerivedStateFromProps does not look like the right tool for what you are trying to do. Instead use componentDidUpdate:
componentDidUpdate(prevProps) {
const { date } = this.props;
if (prevProps.date !== date) {
this.getList(date);
}
}
It's pretty rare to use getDerivedStateFromProps. For more information on when to use getDerivedStateFromProps I recommend this article
how to use getDerivedStateFromProps instead of componentWillReceiveProps in React
How to use lifecycle method getDerivedStateFromProps as opposed to componentWillReceiveProps
reactjs - react js getDerivedStateFromProps is calling continuously - Stack Overflow
getDerivedStateFromProps - responding to change in props
Videos
About the removal of componentWillReceiveProps: you should be able to handle its uses with a combination of getDerivedStateFromProps and componentDidUpdate, see the React blog post for example migrations. And yes, the object returned by getDerivedStateFromProps updates the state similarly to an object passed to setState.
In case you really need the old value of a prop, you can always cache it in your state with something like this:
state = {
cachedSomeProp: null
// ... rest of initial state
};
static getDerivedStateFromProps(nextProps, prevState) {
// do things with nextProps.someProp and prevState.cachedSomeProp
return {
cachedSomeProp: nextProps.someProp,
// ... other derived state properties
};
}
Anything that doesn't affect the state can be put in componentDidUpdate, and there's even a getSnapshotBeforeUpdate for very low-level stuff.
UPDATE: To get a feel for the new (and old) lifecycle methods, the react-lifecycle-visualizer package may be helpful.
As we recently posted on the React blog, in the vast majority of cases you don't need getDerivedStateFromProps at all.
If you just want to compute some derived data, either:
- Do it right inside
render - Or, if re-calculating it is expensive, use a memoization helper like
memoize-one.
Here's the simplest "after" example:
import memoize from "memoize-one";
class ExampleComponent extends React.Component {
getDerivedData = memoize(computeDerivedState);
render() {
const derivedData = this.getDerivedData(this.props.someValue);
// ...
}
}
Check out this section of the blog post to learn more.
Why don't you use componentDidUpdate for this? It seems to me you can achieve the result by:
/**
* @param {Props} prevProps props of the component
**/
componentDidUpdate(prevProps) {
if (prevProps.myStateVar !== this.props.myStateVar) {
this.setState({ myStateVar: this.props.myStateVar });
toggle();
}
}
getDerivedStateFromProps is run on every render. It is also a static method, so it shouldn't be called setState (or other non-static functions). In the documentation, React points out that most of the time you don't need this method to achieve state change based on prop changes here.
So first option, don't call setState, it triggers a re-render and a re-render will run getDerivedStateFromProps. Essentially an infinite re-render loop.
static getDerivedStateFromProps(props, state) {
if (props.myStateVar !== state.myStateVar) {
return {
myStateVar: props.myStateVar,
otherStateVar: [] // from toggle
}
}
// Should not be called everytime this method runs. Only when props change
// toggle() //Need to call the function each time when we get the props update
return null;
}
Your other option is memoization which is covered pretty thoroughly in that link I provided.
getDerivedStateFromProps is not a direct alternative to componentWillReceiveProps, purely because of the fact that its called after every update, whether its the change in state or change in props or re-render of parent.
However whatever is the case, simply returning the state from getDerivedStateFromProps is not the right way, you need to compare the state and props before returning the value. Else with every update the state is getting reset to props and the cycle continues
As per the docs
getDerivedStateFromPropsis invoked right before calling the render method, both on the initial mount and on subsequent updates. It should return an object to update the state, ornullto update nothing.This method exists for rare use cases where the state depends on changes in props over time. For example, it might be handy for implementing a
<Transition>component that compares its previous and next children to decide which of them to animate in and out.Deriving state leads to verbose code and makes your components difficult to think about. Make sure you’re familiar with simpler alternatives:
If you need to perform a side effect (for example, data fetching or an animation) in response to a change in props, use
componentDidUpdatelifecycle instead.If you want to re-compute some data only when a prop changes, use a
memoizationhelper instead.If you want to “reset” some state when a prop changes, consider either making a component
fully controlledorfully uncontrolled with a key instead.
P.S. Note that the arguments to getDerivedStateFromProps are props and state and not nextProps and prevProps
To get into more details,
In order to make changes based on props change, we need to store prevPropsState in state, in order to detect changes. A typical implementation would look like
static getDerivedStateFromProps(props, state) {
// Note we need to store prevPropsState to detect changes.
if (
props.myPropsState !== state.prevPropsState
) {
return {
prevPropsState: state.myState,
myState: props.myPropsState
};
}
return null;
}
Finally, I resolved my issue. It was a painful debugging:
// Child Component
// instead of this
// this.props.onMyDisptach([...myPropsState])
// dispatching true value since myPropsState contains only numbers
this.props.onMyDispatch([...myPropsState, true])
This is because, I have two conditions: 1) on checkbox change (component) 2) on reset button pressed (child component)
I was needing to reset the states when reset button is pressed. So, while dispatching state to the props for reset button, I used a boolean value to know it's a change from the reset. You may use anything you like but need to track that.
Now, here in the component, I found some hints to the differences between componentWillReceiveProps and getDerivedStateFromProps after debugging the console output.
// Component
static getDerivedStateFromProps(props, state) {
const { myPropsState: myState } = props
// if reset button is pressed
const true_myState = myState.some(id=>id===true)
// need to remove true value in the store
const filtered_myState = myState.filter(id=>id!==true)
if(true_myState) {
// we need to dispatch the changes to apply on its child component
// before we return the correct state
props.onMyDispatch([...filtered_myState])
return {
myState: filtered_myState
}
}
// obviously, we need to return null if no condition matches
return null
}
Here's what I found the results of the console output:
getDerivedStateFromProps logs immediately whenever props changes
componentWillReceiveProps logs only after child propagates props changes
getDerivedStateFromProps doesn't respond to the props changes ( I meant for the dispatch changes as in the example code)
componentWillReceiveProps responds to the props changes
Thus, we needed to supply the changes to child component while using getDerivedStateFromProps.
The process of pasting true value in the state I require because getDerivedStateFromProps handle all the changes unlike componentWillReceiveProps handles only the child component dispatches the changes to the props.
By the way, you may use custom property to check if it is changed and update the value if getDerivedStateFromProps but for some reason I have to tweak this technique.
There might be some confusion on my wording but I hope you'll get it.