Refactor componentWillReceiveProps() to getDerivedStateFromProps() in React 16.3

Share this video with your friends

Social Share Links

Send Tweet
Published 6 years ago
Updated 3 years ago

The componentWillReceiveProps() method is being deprecated in future version of React (17). Many of us use this method day-to-day to check for incoming prop changes, store state, and to invoke side effects like logging or fetching data from a server.

In this lesson, we'll look at how to refactor an existing component that uses componentWillReceiveProps() to instead use getDerivedStateFromProps() and componentDidUpdate().

Additional Resources: https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html#migrating-from-legacy-lifecycles

Instructor: [00:00] with the release of React 16.3, React baked in a few new lifecycle methods along with suggestions on how to migrate from componentWillReceiveProps, which will be deprecated in future versions of React.

[00:11] In this lesson, I'm going to look at how to do that. In my code, I have a parent app component with a child component called Box and a button. When the button is clicked, it retrieves a random number between one and three and passes it to the box component. The box component is a contrived example, but it does essentially three things.

[00:31] The first thing it does is it uses the random number passed and fakes an async request to retrieve a formatted string. The fake server request function takes a number and returns a promise that resolves with a number plus itself. This is to simulate what happens you consume an API.

[00:47] The response is stored in a state property called Computed Message. This function is used in componentDidMount to retrieve an initial message and in componentWillReceiveProps to update when props change, which brings us to the second thing the box component does.

[01:02] It uses the ComponentWillReceiveProps method to watch for changes which are invoked when I click the button and updates accordingly. If the random number passed to it is equal to the previous number passed to it, then I show the message, "Same number, try again." The third thing the box component does is that it shows this little "..." loader when it's waiting for a new value.

[01:24] I set Computed Message to null and componentWillReceiveProps to display the loader until the value returns. To refactor this component away from componentWillReceiveProps, I'll have to split its functionality into two lifecycle methods. One, getDerivedStateFromProps, and two, componentDidUpdate.

[01:45] As of React 16.3, the new lifecycle method getDerivedStateFromProps was written to help with some of the new acing features they're trying to introduce in future React versions. This new method is a static and is called when the component is instantiated and when it receives new props.

[02:01] It has two arguments, next props and prove state, and expects an object return for state updates or null for no state updates, which I don't need for this example. Because getDerivedStateFromProps doesn't have a prevProps argument like componentWillReceiveProps, I'll have to work around it.

[02:17] I'll need to keep track of the previous number of props somehow so I can compare it with an incoming number of prop. I can do this by storing it in state. If the number coming in is equal to the previous number stored in state, then show the "Same number, try again," message. If it doesn't equal, then set the computed message to null and store the number for future comparisons.

[02:37] Because this method first runs when the component is instantiated, I can actually set the initial state here before first mount. However, it's probably better practice to do this in the constructor or state property above, but I'll go ahead and set it here for demonstration purposes.

[02:53] React will run this method first before mount and see that I don't have a previous state already for number and go ahead and add number to state. Now that the random number is stored in state, I have something to compare it against when a new number prop comes in. I'm going to go ahead and comment out the componentWillReceiveProps method to see where we're at.

[03:12] Now all we're doing is checking if the numbers match and either showing the "Same number, try again," message or the "..." loader. The getDerivedStateFromProps method is best for updating state based on props and is not for side effects or retrieving data from a server. To do that, the React docs recommend using componentDidUpdate, so that's what we'll use.

[03:34] I'll first check to see if the computed message is null and then go ahead and fetch a new message with fake server requests like I did before. It looks like it's working again. Depending on your use case, you may only need to refactor componentWillReceiveProps to use getDerivedStateFromProps or componentDidUpdate.

[03:55] If you need to store a state based on props, getDerivedStateFromProps is the method for you. If you need to fetch data from a server or do any type of side effects based on props, componentDidUpdate is the correct method...

~ 6 years ago

Hello, Andrew, Looks like this scenario is breaking in higher versions of React (16.4.1) and React-dom("^16.4.1").

Andrew Del Prete
Andrew Del Preteinstructor
~ 6 years ago

Hello, Andrew, Looks like this scenario is breaking in higher versions of React (16.4.1) and React-dom("^16.4.1").

Thanks for letting me know. I'll see what I can do to at least fix the example and explain what happened.

Jan Machycek
Jan Machycek
~ 5 years ago

Hi Andrew, this piece of code should definitely be refactored.

componentDidUpdate(nextProps) {
    const { number } = nextProps;
    if (this.state.computedMessage === null) {
      fakeServerRequest(this.props.number).then(result => {
        this.setState({ computedMessage: result });
      });
    }
  }
  1. componentDidUpdate doesnt receive "nextProps" but "prevProps", this can be confusing to some people

  2. you are assigning a variable "number" which you are not using - instead you are correctly using this.state.number which is the "newest" prop, since CDU receives prevProps

Andrew Del Prete
Andrew Del Preteinstructor
~ 5 years ago

Hey Jan, thanks for the comment. I made some adjustments to the attached CodeSandbox. Good Catch!

Also, as the previous commenter mentioned above, getDerivedStateFromProps() changed significantly in 16.4.x. All updates will fire the getDerivedStateFromProps() even if props don't change. I haven't fixed this in this video since it's specifically for 16.3, but wanted to make sure folks know that this lifecycle method changed quite a bit. Thanks again!

Markdown supported.
Become a member to join the discussionEnroll Today