Hemadri Dasari
Hemadri Dasari

Reputation: 33994

Why is getDerivedStateFromProps is a static method?

I am yet to work on static getDerivedStateFromProps so I am trying to understand about it.

I understand React has deprecated componentWillReceiveProps in React v16+ by introducing a new life cycle method called static getDerivedStateFromProps(). Ok but wondering why React has changed to a static method instead of a normal method.

Why

   static getDerivedStateFromProps(nextProps, prevState){

   }

Why not

   getDerivedStateFromProps(nextProps, prevState){

   }

I am unable to understand why it’s a static method.

Upvotes: 14

Views: 10957

Answers (5)

Devinder Suthwal
Devinder Suthwal

Reputation: 437

getDerivedStateFromProps exists only to enable a component to update its internal state as a result of changes in props. As we update only state on the bases of props, so there is no reason of comparing nextProps and this.props. Here we should compare only next props and previous state, If state and props are different, update state otherwise there should be no update.

If we compare this.props with next props,we require to store the old props value, which impact performance. Keeping copy of past value is called memoization. To avoid misuse of “this” and memoization, getDerivedStateFromProps is made static.

We can consider above as the reason for componentWillReciveProps depreciation too.

Upvotes: 5

supi
supi

Reputation: 2272

To understand what React is trying to achieve with static methods, you should have a good understanding of the following:

  1. Side-effects
  2. Why is asynchronous code considered a bad approach up until the componentDidMount hook
  3. Asynchronous rendering
  4. How static methods aid in discouraging impure and asynchronous coding

  1. Side-effect is nothing but manipulating any data out of scope. So side-effects in getDerivedStateFromProps would mean changes to any other variable other than its own local variables.

Functions that don't cause side-effects are called pure functions and in the case of their arguments, these are cloned before they are manipulated, thereby preserving the state of the objects that such arguments point to.

These functions simply return modified values from within their scope and the caller can decide the course of action with the returned data.


  1. Inducing custom asynchronous code in a library like React with its own lifecycle flows is not a great idea. It should be carefully inserted at the right moment. Let's understand why by analysing the component creation lifecycle of a custom class component (to keep this short lets consider it is also the root element).

At the beginning the ReactDOM.render method invokes the react.createElement() method call.

react.createElement() => calls new ClassElement(props) constructor => returns the ClassElement instance.

After the constructor call, react.createElement() calls the ClassElement.getDerivedStateFromProps(props) method call.

After the above method returns, react.createElement() calls the instance.render() method.

(this can be skipped)

This is followed up with other synchronous calls such as diffing with virtual DOM and updating real DOM etc and there are no hooks provided to tap into these calls(mostly because there is no strong need). A key point to note here is that javascript execution, real DOM updates and UI painting - all - happen within a single thread in the browser thus forcing them to be synchronous. This is one reason why you can write something synchronous like:

let myDiv = document.getElementbyID("myDiv");
myDiv.style.width = "300px"; // myDiv already holds a reference to the real DOM element
console.log(myDiv.style.width); // the width is already set!

because you know at the end of each of those statements, that the earlier statement is completed in DOM and in browser window(UI I mean).

Finally, after the render method returns, react.createElement() calls the componentDidMount to successfully mark the end of lifecycle. Since it's the end, componentDidMount naturally serves as the best junction to attach asynchronous as well as impure functions.

What we must understand is that the lifecycle methods is constantly tweaked for performance and flexibility reasons and is completely under the control of React engineers. It's not just with React, in fact it's with any third party code's flow. So inducing impure functions or asynchronous calls could lead to issues because you would be forcing the React Engineers to be careful with their optimisations.

For e.g. if the React Engineers decide to run getDerivedStateFromProps twice or more times in a single lifecycle flow, both impure functions and asynchronous calls would be fired twice or more, directly affecting some part of the application. However with pure functions this would not be a problem because they only return values and it is upto the React Engineers to decide the course in the multiple getDerivedStateFromProps calls(they can simply discard all the returned values up until the last call and make use of the last one).


  1. Yet another example would be what if the React Engineers decide to make the render call asynchronous. Maybe they would want to club all the render calls (from the parent to all the nested children) and fire them at once asynchronously to improve performance.

Now this would mean that the asynchronous calls written in render method or prior to it(like in constructor or getDerivedStateFromProps) could interfere with the render process because of the unpredictability in the asynchronous process completion. One could complete before or later than the other, triggering their respective callbacks unpredictably. This unpredictability could reflect in the form of multiple rendering, unpredictable state etc.

Importantly, both these ideas aren't just examples, rather were expressed by the React engineers as a possible future optimisation approach. read here: https://stackoverflow.com/a/41612993/923372


  1. In spite of all this, React Engineers know the developers out there could still write asynchronous code or impure functions and to discourage that, they made one of the lifecycle methods static. The constructor, render, getSnapshotBeforeUpdate, componentDidMount and componentDidUpdate methods cant be static because they need to have access to instance properties like this.state, this.props, other custom event handlers etc.(constructor initialises them, render uses them to control the UI logic, other lifecycle methods need these to compare it with earlier states)

However considering getDerivedStateFromProps, this hook is only provided to return an updated clone of the state if the previous props is different from the current props. And by that very definition, this sounds pure with no need for any access to instance properties. Let's analyse why.

For this hook to work, the developer first needs to store the previous props in the instance state(let's say, in the constructor call). This is so because getDerivedStateFromProps receives the instance state as well as new props as arguments. The developer can then proceed to diff the desired property and return an updated clone of the state (without having the need to access this.props or this.state).

By making getDerivedStateFromProps static, not only is React forcing you to write pure functions, it is also making it difficult to write asynchronous calls because you have access to no instance from within this method. Usually the asynchronous call would provide a callback which would most probably be an instance method.

Now this doesn't mean the developers cant write them, instead this is just making it difficult and forcing to keep away from such approaches.


A simple rule of thumb is to stay away from impure and asynchronous functional approaches for the duration of third party induced flows. You should only induce such approaches at the end of such flows.

Upvotes: 19

Tu Nguyen
Tu Nguyen

Reputation: 10179

According to the description of this Proposal:

This proposal is intended to reduce the risk of writing async-compatible React components.

It does this by removing many <sup>1</sup> of the potential pitfalls in the current API while retaining important functionality the API enables. I believe this can be accomplished through a combination of:

  1. Choosing lifecycle method names that have a clearer, more limited purpose.

  2. Making certain lifecycles static to prevent unsafe access of instance properties.

And here

Replace error-prone render phase lifecycle hooks with static methods to make it easier to write async-compatible React components.

Eventually, after lots of discussions, the goal of using static method is also described officially here:

The goal of this proposal is to reduce the risk of writing async-compatible React components. I believe that can be accomplished by removing many1 of the potential pitfalls in the current API while retaining important functionality the API enables. This can be done through a combination of:

  1. Choosing lifecycle method names that have a clearer, more limited purpose.

  2. Making certain lifecycles static to prevent unsafe access of instance properties.

It is not possible to detect or prevent all side-effects (eg mutations of global/shared objects).

Upvotes: 7

Shubham Khatri
Shubham Khatri

Reputation: 281764

getDerivedStateFromProps is a new API that has been introduced in order for it to be extensible when Async rendering as a feature is released. According to Dan Abramov in a tweet,

This method is chosen to be static to help ensure purity which is important because it fires during interruptible phase.

The idea to move all unstable things and side effects after the render method. Giving access to component instance variables during an interruptible phase may lead to people using it with all sorts of side effects causing an inconsistency in async rendering

Upvotes: 4

Sami Kuhmonen
Sami Kuhmonen

Reputation: 31153

You are not supposed to touch any internal data in that method so it is defined as static. This way there is no object you can touch and the only things you’re allowed to do are to use the provided previous state and next props to do whatever you’re doing.

Upvotes: 5

Related Questions