React组件从props初始化状​​态

IT技术 javascript reactjs components
2021-01-21 21:26:15

在 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 = {}(感谢joews),但是,我还是看不出区别。一个比另一个更好吗?

6个回答

应该注意的是,复制永远不会更改为状态的属性是一种反模式(在这种情况下直接访问 .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 的非速记版本。

你能解释一下你的答案与@joews 的答案有何不同吗?
2021-03-14 21:26:15
如果理解状态在初始化后不依赖于props,那么从 props 初始化 state 就不是反模式如果您试图使两者保持同步,那就是一种反模式。
2021-03-31 21:26:15
添加了“如果您所做的只是设置变量,则可以跳过构造函数调用。”
2021-04-05 21:26:15
@ak85 它是相同的语法,但您可以使用 this.state 代替。此语法只是在类构建过程中设置状态的速记语法(也可用于状态以外的变量)
2021-04-05 21:26:15
如果它不起作用,您可能需要安装这个 babel 插件“babel-plugin-transform-class-properties”。
2021-04-09 21:26:15

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

class FirstComponent extends React.Component {

  constructor(props) {
    super(props);

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

请参阅React 文档 - 将本地状态添加到类

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

再次感谢 jowes,第二个文档facebook.github.io/react/docs/...
2021-03-14 21:26:15
joews 的建议在大多数情况下都有效,但要小心将 props 直接发送到 this.state。将 props 复制到 this.state 实际上不是单一的事实来源medium.com/react-ecosystem/...)。此外,Dan Abramov 曾经建议不要在 state 中存储 props 的值。twitter.com/dan_abramov/status/749710501916139520/photo/1)。
2021-03-17 21:26:15
(抱歉我按回车..)我们应该使用 getInitialState 来设置 props 到 state,在更复杂的任务中,如果简单我们可以使用 this.props 到渲染中,对吗?
2021-03-20 21:26:15
附带说明:super(props)在构造函数中使用关于 SO 的讨论
2021-03-24 21:26:15
好答案。可能值得注意的是,这仅用于设置初始状态;setState如果您在任何其他点对其进行变异,您仍然需要使用它,否则可能无法呈现更改。
2021-04-04 21:26:15

引入了 React 16.3 alpha 的更新static getDerivedStateFromProps(nextProps, prevState)文档)作为componentWillReceiveProps.

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

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

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

它是静态的,因此它不能直接访问this(但是它可以访问prevState,它可以存储通常附加到thiseg 的东西refs

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

考虑到getDerivedStateFromProps总是在初始渲染之前调用,我们是否仍然需要在构造函数中创建初始状态
2021-03-16 21:26:15
澄清一下,它被命名getDerivedStateFromProps(在 Props 中标记大写字母)并且参数是nextPropsprevState(不是nextState):reactjs.org/docs/...
2021-03-17 21:26:15
哇! 收到更新的道具时,我们可以使用它来更新状态
2021-03-27 21:26:15

如果您想将所有props添加到状态并保留相同的名称,您可以使用如下的简短形式。

constructor(props) {
    super(props);
    this.state = {
       ...props
    }
    //...
}
复制永远不会更改为状态的属性是一种反模式。最好明确描述您的组件使用哪些字段。
2021-03-24 21:26:15

stateprops构造函数中初始化时,您必须小心即使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} /> 
        );
    }
}

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

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

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