getDerivedStateFromProps

ref – https://alligator.io/react/get-derived-state/
https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html

For a long time, the lifecycle componentWillReceiveProps was the only way to update state in response to a change in props without an additional render. In version 16.3, we introduced a replacement lifecycle, getDerivedStateFromProps to solve the same use cases in a safer way.

getDerivedStateFromProps improves on the older method by providing a function whose only purpose is to update the state based on prop changes, without any side effects.

getDerivedStateFromProps simply returns an object containing the updated state. Notice that the function has no side-effects; this is intentional. Depending on how you want to update the state based on prop, you return an object literal.

getDerivedStateFromProps may be called multiple times for a single update, so it’s important to avoid any side-effects. Instead, you should use componentDidUpdate, which executes only once after the component updates.

However, you probably don’t need Derived State

When to Use Derived State

getDerivedStateFromProps exists for only one purpose: It enables a component to update its internal state as the result of changes in props.

All problems with derived state that we have seen can be ultimately reduced to either:

(1) unconditionally updating state from props or
(2) updating state whenever props and state don’t match.

YOU DON”T NEED DERIVED STATE

– If you’re using derived state to memoize some computation based only on the current props
– If you’re updating derived state unconditionally or updating it whenever props and state don’t match, your component likely resets its state too frequently.

The terms controlled and uncontrolled usually refer to form inputs, but they can also describe where any component’s data lives.

Data passed in as props can be thought of as controlled (because the parent component controls that data). Data that exists only in internal state can be thought of as uncontrolled (because the parent can’t directly change it).

The most common mistake with derived state is mixing these two. For example:

State value can be updated by setState calls, as well as derived from prop. This means there isn’t a single source of truth for the data.

Unconditionally copying props to state

State is initialized to the value specified by props and updated when we type into the input. But if our component’s parent re-renders, anything we’ve typed into the input will be lost! Components usually accept multiple props; another prop changing would ALSO cause a re-render and improper reset.

Therefore, it is a bad idea to unconditionally copy props to state.

Erasing state when props change

We’ve just made a big improvement. Now our component will erase what we’ve typed only when the props actually change.

However, because our prop uses ’email’ property compare, if two accounts had the same exactly email, this situation would happen.

1) Say you’re updating the first email account, then you click on another account type.
2) The parent component’s prop makes the update, but because your email is the same “fake.email@example.com” for id 1 and id 2, our componentWillReceiveProps will just skip. When users switch from id 1 to id 2, they still see what you updated in the input text. Whereas it should have cleared, or defaulted by to the string “fake.email@example.com”.

The key is that for any piece of data, you need to pick a single component that owns it as the source of truth, and avoid duplicating it in other components. Let’s take a look at each of the alternatives.

Solutions

Fully controlled component – One way to avoid the problems mentioned above is to remove state from our component entirely. If the email address only exists as a prop, then we don’t have to worry about conflicts with state.

This approach simplifies the implementation of our component, but if we still want to store a draft value, the parent form component will now need to do that manually.

Fully uncontrolled component with a key

In order to reset the value when moving to a different item, we can use the special React attribute called key. When a key changes, React will create a new component instance rather than update the current one. Keys are usually used for dynamic lists but are also useful here. In our case, we could use the user ID to recreate the email input any time a new user is selected:

Each time the user id changes, the EmailInput will be recreated and its state will be reset to the latest defaultEmail value.

But let’s say the component is very expensive to initialize, and we can’t create it often…

A workable but cumbersome solution would be to watch for changes to “userID” on property “prevPropsUserID” in getDerivedStateFromProps: