Huy Vo
Huy Vo

Reputation: 2500

A thought about getDerivedStateFromProps

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

Answers (2)

Agney
Agney

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.

  1. First we initialise this.state.data variable to [].
  2. Then using the props, we perform an API call in componentDidMount() to assign it to this.state.data.
  3. Now, these parameters coming from the parent are subject to change, so you had to repeat the procedure in 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

user1902408
user1902408

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

Related Questions