React组件从props初始化状态

时间:2016-10-15 19:43:48

标签: javascript reactjs components

在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),但是,我仍然没有看到差异。一个人比其他人好吗?

9 个答案:

答案 0 :(得分:127)

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

string theStringResult = Class.ExternalMethod();
theStringResult.ToArray()

这是一个简写,相当于下面@joews的回答。它似乎只适用于更新版本的es6转换器,我在一些webpack设置上遇到了问题。如果这对您不起作用,您可以尝试添加babel插件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下面的非简写版本。

答案 1 :(得分:114)

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

class FirstComponent extends React.Component {

  constructor(props) {
    super(props);

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

请参阅React docs - Adding Local State to a Class

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

答案 2 :(得分:25)

针对React 16.3的更新 alpha引入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在评论中的更正

答案 3 :(得分:11)

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

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

答案 4 :(得分:3)

在构造函数中从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} /> 
        );
    }
}

或使用key道具作为初始化触发器:

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

在上面的代码中,如果更改了something,则SecondComponent重新安装作为新实例,state将由{{1 }}。

答案 5 :(得分:2)

  

如果您直接通过道具初始化状​​态,它将在React 16.5中显示警告(2018年9月5日)

答案 6 :(得分:2)

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

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

如果您通过道具在componentDidMount()方法中进行设置,它将无法正常工作。

答案 7 :(得分:0)

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

答案 8 :(得分:0)

您可以使用componentWillReceiveProps。

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

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