React组件从props初始化状态

Lev*_*ira 168 javascript components reactjs

在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;
Run Code Online (Sandbox Code Playgroud)

第二:

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;
Run Code Online (Sandbox Code Playgroud)

更新:我将setState()更改为this.state = {}(感谢joews),但是,我仍然没有看到区别.一个比其他更好吗?

Zan*_*per 167

应该注意的是,复制永不改变状态的属性是一种反模式(在这种情况下只是直接访问.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),
  };
}
Run Code Online (Sandbox Code Playgroud)

这是一个简写等同于@joews下面的答案.它似乎只适用于更新版本的es6转换器,我在一些webpack设置上遇到了问题.如果这对您不起作用,您可以尝试添加babel插件babel-plugin-transform-class-properties,或者您可以使用@joews下面的非简写版本.

  • 从 props 初始化 state 不是反模式**如果可以理解**在初始化后状态不依赖于 props。如果您试图保持两者同步,**那是**一种反模式。 (9认同)
  • 添加"如果你所做的只是设置变量,你可以跳过构造函数调用." (3认同)
  • 如果不起作用,则可能需要安装此babel插件“ babel-plugin-transform-class-properties”。 (2认同)

joe*_*ews 126

你不需要调用setState组件constructor- 它是this.state直接设置的惯用语:

class FirstComponent extends React.Component {

  constructor(props) {
    super(props);

    this.state = {
      x: props.initialX
    };
  }
  // ...
}
Run Code Online (Sandbox Code Playgroud)

请参阅React docs - 将本地状态添加到类.

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

  • 好答案.值得注意的是,这只是为了设定初始状态; 如果你在任何其他点改变它,你仍然需要使用`setState`,否则更改可能无法呈现. (4认同)
  • joews 的建议在大多数情况下都有效,但要小心将 props 直接发送到 this.state。将道具复制到 this.state 实际上是*单一的事实来源*(https://medium.com/react-ecosystem/how-to-handle-state-in-react-6f2d3cd73a0c)。另外,Dan Abramov 曾经建议不要在 state 中存储 props 的值。(https://twitter.com/dan_abramov/status/749710501916139520/photo/1)。 (3认同)
  • 上帝该死的选择这个作为公认的答案! (2认同)

Ash*_*man 32

更新React 16.3 alpha引入static getDerivedStateFromProps(nextProps, prevState)(docs)作为替代品componentWillReceiveProps.

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

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

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

它是静态的,因此它没有直接访问权限this(但它有权访问prevState,可以存储通常附加到的东西,this例如refs)

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

  • 为了澄清,它被命名为`getDerivedStateFromProps`(标记道具中的大写字母),而params是`nextProps`,`prevState`(不是`nextState`):https://reactjs.org/docs/react-component.html #静态getderivedstatefromprops (3认同)
  • 哇!当收到**更新的道具**时,我们可以使用它来更新状态! (2认同)
  • 考虑到 `getDerivedStateFromProps` 总是在初始渲染之前被调用,我们是否仍然需要在构造函数中创建初始状态? (2认同)

小智 16

如果要将所有道具添加到状态并保留相同的名称,可以使用如下所示的简短形式.

constructor(props) {
    super(props);
    this.state = {
       ...props
    }
    //...
}
Run Code Online (Sandbox Code Playgroud)


Yon*_*Noh 13

您必须时初始化要小心state来自props于构造函数。即使props更改为新的,状态也不会改变,因为 mount 再也不会发生了。因此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} /> 
        );
    }
}
Run Code Online (Sandbox Code Playgroud)

或者使用keyprops 作为触发器来初始化:

class SecondComponent extends React.Component {
  state = {
    // initialize using props
  };
}
Run Code Online (Sandbox Code Playgroud)
<SecondComponent key={something} ... />
Run Code Online (Sandbox Code Playgroud)

在上面的代码中,如果something更改,SecondComponent则将重新挂载为新实例state并由props.


Kri*_*gid 5

像这样在构造函数中设置状态数据

constructor(props) {
    super(props);
    this.state = {
      productdatail: this.props.productdetailProps
    };
}
Run Code Online (Sandbox Code Playgroud)

如果您componentDidMount()通过 props在 side方法中设置,它将无法工作。