从组件反应组件初始化状态


204

在React中,这两种实现之间有什么真正的区别?一些朋友告诉我,FirstComponent是模式,但是我不明白为什么。SecondComponent看起来更简单,因为渲染仅被调用一次。

第一:

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;

第二:

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;

更新:我将setState()更改为this.state = {}(感谢乔伊斯),但是,我仍然看不到区别。一个比另一个好吗?


10
为什么要在州内存放道具?您应该直接使用道具,而不是缓存值。了解为何在React.js中将道具设置为状态是亵渎神灵,在getInitialState中设置道具是反模式
Aurora0001 '01 -10-15

12
一个示例-可切换的组件(例如,一个弹出框或抽屉)。父级知道组件应该开始打开还是关闭。组件本身可能会在某个时间点知道它是否处于打开状态。在那种情况下,我认为this.state = { isVisible: props.isVisible }是有道理的。取决于应用程序如何分配UI状态。
16


5
在2017年,Facebook演示了使用道具在其文档中设置初始状态的方法:reactjs.org/docs/react-component.html#constructor
Rohmer

1
@ Aurora0001在需要处理表单的情况下,比如说一个编辑表单,它可以自己发出网络请求,但是您需要使用作为该组件道具的值来初始化输入。为了使表格保持动态,必须将这些值保持在状态中。
Eric McWinNEr

Answers:


196

应该注意的是,复制永远不会更改为状态的属性是一种反模式(在这种情况下,只需直接访问.props即可)。如果您有一个状态变量最终会更改,但以.props中的值开头,则您甚至不需要构造函数调用-这些局部变量在调用父级的构造函数之后初始化:

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

这是等效于下面@joews中答案的简写。它似乎只能在最新版本的es6转译器上运行,在某些webpack设置中我遇到了问题。如果这对您不起作用,则可以尝试添加babel插件babel-plugin-transform-class-properties,也可以使用下面@joews提供的非简写版本。


1
您能否进一步说明您的答案与@joews答案有何不同?
Jalal

3
添加了“如果您要做的只是设置变量,则可以跳过构造函数调用。”
Zane Hooper

3
如果不起作用,则可能需要安装此babel插件“ babel-plugin-transform-class-properties”。
Faheem

2
如果了解到初始化后状态不依赖于props,则从props初始化状态不是反模式。如果您试图使两者保持同步,那是一种反模式。
Yatrix

1
@ ak85是相同的语法,但是您可以使用this.state代替。该语法只是用于在类构造过程中设置状态的简写语法(并且还可用于状态以外的变量)
Zane Hooper

137

您不需要调用setStateComponent的constructor- this.state直接设置是惯用法:

class FirstComponent extends React.Component {

  constructor(props) {
    super(props);

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

参见React docs-向类添加局部状态

您描述的第一种方法没有任何优势。它将在首次安装组件之前立即进行第二次更新。


4
好答案。可能值得注意的是,这仅用于设置初始状态。setState如果您在其他任何地方对其进行了突变,则仍然需要使用,否则更改可能无法呈现。
Aurora0001 '16

再次感谢jowes,第二文档facebook.github.io/react/docs/...
利维·莫雷拉

(对不起,我按Enter键。)我们应该使用getInitialState来设置道具的状态,在更复杂的任务中,如果简单的话,我们可以仅使用this.props进行渲染,对吗?
Levy Moreira

1
附带说明:super(props)在构造函数中使用。关于SO的讨论
cutemachine '17

2
joews的建议在大多数情况下都是可行的,但请小心将道具直接发送到this.state。将道具复制到this.state实际上是事实的唯一来源medium.com/react-ecosystem/…)。另外,丹·阿布拉莫夫(Dan Abramov)曾经建议不要将道具的值存储在状态中。(twitter.com/dan_abramov/status/749710501916139520/photo/1)。
弘树

33

更新了React 16.3 alpha static getDerivedStateFromProps(nextProps, prevState)文档),以替代componentWillReceiveProps

实例化组件之后以及接收到新的道具时,将调用getDerivedStateFromProps。它应该返回一个对象来更新状态,或者返回null来指示新道具不需要任何状态更新。

请注意,如果父组件导致您的组件重新渲染,则即使props没有更改,也会调用此方法。如果您只想处理更改,则可能需要比较新值和先前值。

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

它是静态的,因此它不能直接访问this(但是确实可以访问prevState,它可以存储通常连接到的东西,this例如refs

编辑以在评论中反映@nerfologist的更正


3
为了澄清起见,它的名称是getDerivedStateFromProps(在Props中标记为大写字母),并且参数是nextPropsprevState(不是nextState):reactjs.org/docs/…–
nerfologist

1
哇!当 收到更新的道具时,我们可以用它来更新状态!
Aromal Sasidharan

2
考虑到getDerivedStateFromProps始终在初始渲染之前调用,我们是否仍需要在构造函数中创建初始状态?
bvdb

19

如果要添加所有道具以声明并保留相同的名称,则可以使用如下所示的简短形式。

constructor(props) {
    super(props);
    this.state = {
       ...props
    }
    //...
}

1
这是一种复制永远不会更改为状态的属性的反模式。最好明确描述组件使用的字段。
Michael Freidgeim




1

您可以使用componentWillReceiveProps。

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

    componentWillReceiveProps(nextProps){
        this.setState({ productdatail: nextProps.productdetailProps })
    }

1
componentWillReceiveProps已弃用,不能用于将来的版本
Vivek Ghanchi

1

您必须时初始化要小心state来自props于构造函数。即使props更改为新状态,也不会更改状态,因为安装不再发生。因此getDerivedStateFromProps存在。

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} /> 
        );
    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.