The useEffect hook is also the equivalent of the componentWillReceiveProps or componentDidUpdate hooks. All we have to do is to pass in an array with the value that we want to watch for changes.
The getDerivedStateFromProps() method is called right before rendering the element(s) in the DOM. This is the natural place to set the state object based on the initial props . It takes state as an argument, and returns an object with changes to the state .
js static getDerivedStateFromProps() The getDerivedStateFromProps() method is used when the state of a component depends on changes of props. getDerivedStateFromProps(props, state) is a static method that is called just before render() method in both mounting and updating phase in React.
There are a few life cycle methods that have been deprecated and renamed in React 17. We don't need to use these anymore— getDerivedStateFromProps and getSnapshotBeforeUpdate essentially replaced them.
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:
render
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.
As mentioned by Dan Abramov
Do it right inside render
We actually use that approach with memoise one for any kind of proxying props to state calculations.
Our code looks this way
// ./decorators/memoized.js
import memoizeOne from 'memoize-one';
export function memoized(target, key, descriptor) {
descriptor.value = memoizeOne(descriptor.value);
return descriptor;
}
// ./components/exampleComponent.js
import React from 'react';
import { memoized } from 'src/decorators';
class ExampleComponent extends React.Component {
buildValuesFromProps() {
const {
watchedProp1,
watchedProp2,
watchedProp3,
watchedProp4,
watchedProp5,
} = this.props
return {
value1: buildValue1(watchedProp1, watchedProp2),
value2: buildValue2(watchedProp1, watchedProp3, watchedProp5),
value3: buildValue3(watchedProp3, watchedProp4, watchedProp5),
}
}
@memoized
buildValue1(watchedProp1, watchedProp2) {
return ...;
}
@memoized
buildValue2(watchedProp1, watchedProp3, watchedProp5) {
return ...;
}
@memoized
buildValue3(watchedProp3, watchedProp4, watchedProp5) {
return ...;
}
render() {
const {
value1,
value2,
value3
} = this.buildValuesFromProps();
return (
<div>
<Component1 value={value1}>
<Component2 value={value2}>
<Component3 value={value3}>
</div>
);
}
}
The benefits of it are that you don't need to code tons of comparison boilerplate inside getDerivedStateFromProps
or componentWillReceiveProps
and you can skip copy-paste initialization inside a constructor.
NOTE:
This approach is used only for proxying the props to state, in case you have some inner state logic it still needs to be handled in component lifecycles.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With