【问题标题】:React 组件从 props 初始化状态
【发布时间】:2023-03-08 19:50:01
【问题描述】:

在 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),但是,我仍然看不出有什么区别。一个比另一个更好吗?

【问题讨论】:

  • 嗨,谢谢你的链接,这些组件只是一个示例,但是你如何链接显示facebook.github.io/react/tips/… 如果我需要这些数据,我可以将道具设置为状态......问题在这里是关于我应该如何将日期从道具存储到我的状态。
  • 一个例子——一个可切换的组件(例如一个弹出框或抽屉)。父级知道组件应该开始打开还是关闭;组件本身可能知道它在某个时间点是否打开。在那种情况下,我认为this.state = { isVisible: props.isVisible } 是有道理的。取决于应用如何分配 UI 状态。
  • 你应该阅读这个medium.com/@justintulk/…
  • 2017 年,Facebook 在其文档中演示了使用道具设置初始状态:reactjs.org/docs/react-component.html#constructor
  • @Aurora0001 在您需要处理表单的情况下,比如说一个编辑表单,它会自行发出网络请求,但您需要使用将作为道具的值初始化输入那个组件。为了保持表单动态,这些值必须保持在状态。

标签: javascript reactjs components


【解决方案1】:

在构造函数中从 props 初始化 state 时必须小心。 即使将 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} /> 
        );
    }
}

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

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

在上面的代码中,如果something发生了变化,那么SecondComponent重新挂载作为一个新的实例,state将被props初始化。

【讨论】:

    【解决方案2】:

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

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

    如果你通过props在componentDidMount()方法中设置它是行不通的。

    【讨论】:

      【解决方案3】:

      您可以使用 componentWillReceiveProps。

      constructor(props) {
          super(props);
          this.state = {
            productdatail: ''
          };
      }
      
      componentWillReceiveProps(nextProps){
          this.setState({ productdatail: nextProps.productdetailProps })
      }
      

      【讨论】:

      • componentWillReceiveProps 已弃用,不能用于未来版本
      【解决方案4】:

      您可以在需要时使用key 值来重置状态,传递道具来说明这不是一个好习惯,因为您在一个地方有不受控制和受控的组件。数据应该在一个地方处理 读这个 https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html#recommendation-fully-uncontrolled-component-with-a-key

      【讨论】:

        【解决方案5】:

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

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

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

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

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

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

        【讨论】:

        • 澄清一下,它被命名为getDerivedStateFromProps(在Props中标记大写字母),参数是nextPropsprevState(不是nextState):reactjs.org/docs/…
        • 哇!我们可以在收到 updated props 时使用它来更新状态!
        • 考虑到getDerivedStateFromProps总是在初始渲染之前被调用,我们还需要在构造函数中创建初始状态吗?
        【解决方案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 的答案有何不同吗?
        • 添加了“如果您所做的只是设置变量,则可以跳过构造函数调用。”
        • 如果不行,可能需要安装这个babel插件“babel-plugin-transform-class-properties”。
        • 从 props 初始化状态不是反模式如果理解在初始化后状态不依赖于 props。如果您试图使两者保持同步,那是一种反模式。
        • @ak85 语法相同,但您可以使用 this.state 代替。该语法只是在类构造过程中设置状态的简写语法(也可用于状态以外的变量)
        【解决方案7】:

        如果你直接从 props 初始化 state,它会在 React 16.5(2018 年 9 月 5 日)中显示警告

        【讨论】:

        【解决方案8】:

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

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

        【讨论】:

        • 复制永远不会改变状态的属性是一种反模式。最好明确描述您的组件使用哪些字段。
        【解决方案9】:

        您无需在组件的constructor 中调用setState - 直接设置this.state 是惯用的:

        class FirstComponent extends React.Component {
        
          constructor(props) {
            super(props);
        
            this.state = {
              x: props.initialX
            };
          }
          // ...
        }
        

        React docs - Adding Local State to a Class

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

        【讨论】:

        • 好答案。可能值得注意的是,这仅用于设置初始状态;如果你在其他任何时候改变它,你仍然需要使用setState,否则更改可能不会呈现。
        • 再次感谢 jowes,其次是文档 facebook.github.io/react/docs/…
        • (sorry I press enter.. ) 我们应该使用 getInitialState 来设置 props 的状态,在更复杂的任务中,如果简单我们可以使用 this.props 进入渲染,对吗?
        • 附注:在构造函数中使用super(props)Discussion on SO
        • joews 的建议在大多数情况下都有效,但要小心直接向 this.state 发送道具。将 props 复制到 this.state 实际上是违反单一事实来源 (medium.com/react-ecosystem/…)。此外,Dan Abramov 曾经建议不要将 props 的值存储在 state 中。 (twitter.com/dan_abramov/status/749710501916139520/photo/1)。
        猜你喜欢
        • 1970-01-01
        • 2015-05-10
        • 2020-04-04
        • 2019-01-04
        • 2018-08-22
        • 2019-01-16
        • 1970-01-01
        • 2020-05-28
        • 1970-01-01
        相关资源
        最近更新 更多