Reputation: 2500
According to this post about what's news in React 16.3, in the next update componentWillReceiveProps
will have a replacement and that is getDerivedStateFromProps
(the replacement will only happens in 17.0).
The interesting part is that this brand new, static lifecycle method
is called both on initial mounting and on re-rendering of the component, so you can use it instead of creating state based on props in constructor.
I'm getting confused. So from now on should I need to split my constructor and put the create state logic to this new function instead? I mean the logic when you create state first time your component is created and the logic when you create state from API props is not the same. Putting them together in one method seems not very ideal.
And one more thing is that if I choose to create my state from constructor, this new method will still be called anyway. What a jerk!
What do you think?
Upvotes: 2
Views: 13561
Reputation: 19214
Let us say we have a list component, that renders a few list items by supplying a few parameters received from it's parent to the API.
this.state.data
variable to []
.componentDidMount()
to assign it to this.state.data
. componentWillReceiveProps
. I think this is the likely scenario that getDerivedStateFromProps
is targeting. Now instead of updating state from props twice, you only need to write it once in the function: getDerivedStateFromProps
. As the name suggests, use it when state has to be derived from the props.
Points to keep in mind:
You still need to set initial state in constructor. The logic for both initial state and deriving state from props can be very different. For example, if you do not initialise the data
variable to []
and you are mapping over this.state.data
it would fail as the API has not returned the results to be set in getDerivedStateFromProps
yet.
Even though getDerivedStateFromProps
can't use this
, it works in the same way that this.setState
does.
That is, if you return
{
data: response.data
}
it wouldn't update the other state variables that you have set in constructor. Also you have an option to return null
to signify no change.
From:
class ExampleComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
externalData: []
}
}
componentWillMount() {
asyncLoadData(this.props.someId).then(externalData =>
this.setState({ externalData })
);
}
componentWillReceiveProps() {
asyncLoadData(this.props.someId).then(externalData =>
this.setState({ externalData })
);
}
}
To:
class ExampleComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
externalData: []
}
}
static deriveStateFromProps(props, state, prevProps) {
if (prevProps === null || props.someValue !== prevProps.someValue) {
return {
derivedData: computeDerivedState(props)
};
}
// Return null to indicate no change to state.
return null;
}
}
Note: I'm just noting an instance from pure React perspective.
Also read You Probably Don't Need Derived State from React Blog.
Upvotes: 11
Reputation:
The key difference is that in React 16 componentWillReceiveProps is not called on the inital render, only when new props are received. This means you would in your case, create derived state on first load in the constructor, then use componentWillReceiveProps on update.
With the new getDerivedStateFromProps this logic can be written in this function only, as it runs on both inital mount and updates.
React doesn’t call componentWillReceiveProps() with initial props during mounting. It only calls this method if some of component’s props may update. Calling this.setState() generally doesn’t trigger componentWillReceiveProps().
In regards to your question regarding API's to me that would be dependent on how the component is set up, seems to me like it would be logical to make the API call in a parent component, that way you can control how the props are passed down and make the component receiving the props as dumb as possible. State can still be set in a method after making the API call.
As Dan Abramov states, passing props to state is usually a bad idea, this function will be used infrequently is designed to be used when your state depends on how props change over time.
Props to state as an anti-practice and a potential use case.
React - componentWillReceiveProps()
Upvotes: 6