263

In React, are there any real differences between these two implementations? Some friends tell me that the FirstComponent is the pattern, but I don't see why. The SecondComponent seems simpler because the render is called only once.

First:

import React, { PropTypes } from 'react'

class FirstComponent extends React.Component {

  state = {
    description: ''
  }

  componentDidMount() {
    const { description} = this.props;
    this.setState({ description });
  }

  render () {
    const {state: { description }} = this;    
    return (
      <input type="text" value={description} /> 
    );
  }
}

export default FirstComponent;

Second:

import React, { PropTypes } from 'react'

class SecondComponent extends React.Component {

  state = {
    description: ''
  }

  constructor (props) => {
    const { description } = props;
    this.state = {description};
  }

  render () {
    const {state: { description }} = this;    
    return (
      <input type="text" value={description} />   
    );
  }
}

export default SecondComponent;

Update: I changed setState() to this.state = {} (thanks joews), However, I still don't see the difference. Is one better than other?

Archmede
  • 1,592
  • 2
  • 20
  • 37
Levy Moreira
  • 2,733
  • 2
  • 14
  • 10
  • Hi, thanks for the links, these components are just a sample, but how you link show https://facebook.github.io/react/tips/props-in-getInitialState-as-anti-pattern.html I can set the props into the state if I need this data after ... the question here is about how I when I should store the date from props to my state. – Levy Moreira Oct 15 '16 at 20:00
  • 12
    An example - a toggleable component (e.g. a popover or drawer). The parent knows whether the component should start open or closed; the component itself may know whether it is open or not at a point in time. In that case I think `this.state = { isVisible: props.isVisible }` makes sense. Depends on how the app distributes UI state. – joews Oct 15 '16 at 20:00
  • 2
    You should read this https://medium.com/@justintulk/react-anti-patterns-props-in-initial-state-28687846cc2e – FDisk Nov 27 '17 at 10:53
  • 5
    In 2017, Facebook demonstrates using props to set initial state in their documentation: https://reactjs.org/docs/react-component.html#constructor – tim-phillips Dec 06 '17 at 19:30
  • 1
    @Aurora0001 What of in a situation where you need to handle a form, say an edit form that would make network requests on it's own but you need to initialize the inputs with values that would come as props to that component. In order to keep the form dynamic, those values have to be kept in state. – Eric McWinNEr Aug 12 '19 at 00:16

9 Answers9

232

It should be noted that it is an anti-pattern to copy properties that never change to the state (just access .props directly in that case). If you have a state variable that will change eventually but starts with a value from .props, you don't even need a constructor call - these local variables are initialized after a call to the parent's constructor:

class FirstComponent extends React.Component {
  state = {
    x: this.props.initialX,
    // You can even call functions and class methods:
    y: this.someMethod(this.props.initialY),
  };
}

This is a shorthand equivalent to the answer from @joews below. It seems to only work on more recent versions of es6 transpilers, I have had issues with it on some webpack setups. If this doesn't work for you, you can try adding the babel plugin babel-plugin-transform-class-properties, or you can use the non-shorthand version by @joews below.

Zane
  • 4,652
  • 1
  • 29
  • 26
  • 1
    can you explain more how your answer is different from @joews answer? – Jalal Dec 11 '17 at 18:50
  • 3
    Added "You can skip the constructor call if all you are doing is setting variables." – Zane Dec 12 '17 at 17:36
  • 3
    If it does not work, you probably need to install this babel plugin "babel-plugin-transform-class-properties". – Faheem Oct 21 '18 at 09:35
  • i'm using return this.state.counters.map(counter => )} and using state = { count : this.props.value }; in counter Component. But i'm still getting an error. – Kiran Maniya Nov 26 '18 at 09:57
  • Hi Kiran, did you make sure that the babel plugin `babel-plugin-transform-class-properties` is installed? This is special syntax that isn't available in all ES6 implementations. The answer from @joews below should work with any ES6 implementation, but I prefer this syntax. – Zane Nov 26 '18 at 14:56
  • 14
    It isn't an anti-pattern to initialize state from props **if it's understood** that the state doesn't rely on the props after the initialization. If you are trying to keep the two in sync, **that's** an anti-pattern. – Yatrix Jan 10 '19 at 16:34
  • this doesn't seem to work when parent state changes. i can see in react dev tools parent state: true, child prop: true, child state: false – Sonic Soul Mar 11 '19 at 20:40
  • @ZaneHooper in your example are you able to show how you can set initialX / initialY as a const so you don't need to call this.props every time? eg I would usually do `const { initialX } = this.props` in the render method but not sure of what the syntax should be for your example? – ak85 Jun 04 '19 at 03:47
  • 1
    @ak85 it is the same syntax but you'd use this.state instead. This syntax is just a shorthand syntax for setting the state during the class construction process (and can be used for variables other than state as well) – Zane Jun 05 '19 at 23:44
  • @ZaneHooper -- I dont understand why my state variable is not being initialised with the prop values. I can see them in the console in props, and I also assign them when state is declared, but just doesn't initialize. I have to use getDerivedStateFromProps(props, state) but as it keeps getting called, the state is being reset all the time. I am not understanding how to solve this problem – srinivas May 13 '20 at 19:51
  • @srinivas I would recommend creating a separate question for that to provide further context (e.g. what code you're using, what the usage of your component looks like) – Zane May 14 '20 at 00:20
158

You don't need to call setState in a Component's constructor - it's idiomatic to set this.state directly:

class FirstComponent extends React.Component {

  constructor(props) {
    super(props);

    this.state = {
      x: props.initialX
    };
  }
  // ...
}

See React docs - Adding Local State to a Class.

There is no advantage to the first method you describe. It will result in a second update immediately before mounting the component for the first time.

joews
  • 29,767
  • 10
  • 79
  • 91
  • 8
    Good answer. It might be worth noting that this is only for setting the initial state; you still need to use `setState` if you mutate it at any other point, otherwise the changes may not render. – Aurora0001 Oct 15 '16 at 19:50
  • Thanks again jowes, second the documentation https://facebook.github.io/react/docs/reusable-components.html#setting-the-initial-state – Levy Moreira Oct 15 '16 at 22:07
  • (sorry I press enter.. ) we should use the getInitialState for set the props to state, in more complex tasks, if is simple we can just use the this.props into the render, correct? – Levy Moreira Oct 15 '16 at 22:08
  • That's right. Use `this.props` wherever you can; only put props in state as a starting value of something that will change later. – joews Oct 15 '16 at 22:11
  • 1
    On a marginal note: use `super(props)` in the constructor. [Discussion on SO](https://stackoverflow.com/questions/30571875/whats-the-difference-between-super-and-superprops-in-react-when-using-e) – cutemachine Sep 01 '17 at 06:03
  • 3
    joews' suggestion works in most cases, but be careful about sending props to this.state directly. Copying props to this.state is actually againt *single source of truth* (https://medium.com/react-ecosystem/how-to-handle-state-in-react-6f2d3cd73a0c). Also, Dan Abramov once suggested not storing props' values in state. (https://twitter.com/dan_abramov/status/749710501916139520/photo/1). – Hiroki Nov 19 '17 at 06:32
  • 1
    @Hiroki it's not always. Think about a menu component that could be open or closed. The menu's component could be the source of truth for whether the menu is _initially_ open or closed; the menu itself could be the source of truth as it opens and closes over time. – joews Mar 05 '18 at 09:06
42

Update for React 16.3 alpha introduced static getDerivedStateFromProps(nextProps, prevState) (docs) as a replacement for componentWillReceiveProps.

getDerivedStateFromProps is invoked after a component is instantiated as well as when it receives new props. It should return an object to update state, or null to indicate that the new props do not require any state updates.

Note that if a parent component causes your component to re-render, this method will be called even if props have not changed. You may want to compare new and previous values if you only want to handle changes.

https://reactjs.org/docs/react-component.html#static-getderivedstatefromprops

It is static, therefore it does not have direct access to this (however it does have access to prevState, which could store things normally attached to this e.g. refs)

edited to reflect @nerfologist's correction in comments

Community
  • 1
  • 1
Ashley Coolman
  • 11,095
  • 5
  • 59
  • 81
  • 3
    Just to clarify, it's named `getDerivedStateFromProps` (mark the capital letter in Props) and the params are `nextProps`, `prevState` (not `nextState`): https://reactjs.org/docs/react-component.html#static-getderivedstatefromprops – nerfologist Apr 26 '18 at 08:44
  • 2
    Wow! we can use this to update state when **updated props** are received! – Aromal Sasidharan Aug 22 '18 at 08:48
  • 2
    Do we still have to create the initial state in the constructor, considering that the `getDerivedStateFromProps` is always called before the initial rendering ? – bvdb Jan 09 '19 at 10:21
25

YOU HAVE TO BE CAREFUL when you initialize state from props in constructor. Even if props changed to new one, the state wouldn't be changed because mount never happen again. So getDerivedStateFromProps exists for that.

class FirstComponent extends React.Component {
    state = {
        description: ""
    };
    
    static getDerivedStateFromProps(nextProps, prevState) {
        if (prevState.description !== nextProps.description) {
          return { description: nextProps.description };
        }
    
        return null;
    }

    render() {
        const {state: {description}} = this;    

        return (
            <input type="text" value={description} /> 
        );
    }
}

Or use key props as a trigger to initialize:

class SecondComponent extends React.Component {
  state = {
    // initialize using props
  };
}
<SecondComponent key={something} ... />

In the code above, if something changed, then SecondComponent will re-mount as a new instance and state will be initialized by props.

Yonggoo Noh
  • 1,811
  • 3
  • 22
  • 37
24

You could use the short form like below if you want to add all props to state and retain the same names.

constructor(props) {
    super(props);
    this.state = {
       ...props
    }
    //...
}
Mahdi Bashirpour
  • 17,147
  • 12
  • 117
  • 144
dacharjaya
  • 389
  • 2
  • 4
  • 1
    it is an anti-pattern to copy properties that never change to the state. It’s better to explicitly describe which fields your component uses. – Michael Freidgeim May 18 '19 at 22:54
5

set the state data inside constructor like this

constructor(props) {
    super(props);
    this.state = {
      productdatail: this.props.productdetailProps
    };
}

it will not going to work if u set in side componentDidMount() method through props.

Olcay Ertaş
  • 5,987
  • 8
  • 76
  • 112
Krishna Jangid
  • 4,961
  • 5
  • 27
  • 33
3

If you directly init state from props, it will shows warning in React 16.5 (5th September 2018)

Sujith S
  • 555
  • 5
  • 8
3

you could use key value to reset state when need, pass props to state it's not a good practice , because you have uncontrolled and controlled component in one place. Data should be in one place handled read this https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html#recommendation-fully-uncontrolled-component-with-a-key

Palaniichuk Dmytro
  • 2,943
  • 12
  • 36
  • 66
0

You can use componentWillReceiveProps.

constructor(props) {
    super(props);
    this.state = {
      productdatail: ''
    };
}

componentWillReceiveProps(nextProps){
    this.setState({ productdatail: nextProps.productdetailProps })
}
Olcay Ertaş
  • 5,987
  • 8
  • 76
  • 112
Ankit Kumar Rajpoot
  • 5,188
  • 2
  • 38
  • 32