在属性更改时更改状态并首先安装在 React 上 - 缺少功能?

Change state when properties change and first mount on React - Missing function?

我遇到了一个关于基于属性的状态的问题。

场景

我有一个组件 parent,它创建一个 属性 到 child 组件的传递。 Child 组件根据收到的 属性 做出反应。 在 React 中,"only" 更改组件状态的正确方法是使用函数 componentWillMount 或 componentDidMount 和 componentWillReceiveProps 就我所见(除其他外,但让我们关注这些,因为 getInitialState 只执行一次).

我的problem/Question

如果我从 parent 收到一个新的 属性 并且我想改变状态,只有函数 componentWillReceiveProps 会被执行并允许我执行 setState。渲染不允许设置状态。

如果我想在开始时设置状态和接收新的时间怎么办属性? 所以我必须在 getInitialState 或 componentWillMount/componentDidMount 上设置它。然后,您必须根据使用 componentWillReceiveProps 的属性更改状态。

当您的状态高度依赖于您的属性时,这就是一个问题,这几乎总是如此。这可能会变得愚蠢,因为您必须根据新的 属性.

重复要更新的状态

我的解决方案

我创建了一个在 componentWillMount 和 componentWillReceiveProps 上调用的新方法。我没有发现在 属性 在渲染之前更新之后以及第一次安装组件时调用了任何方法。那么就不需要做这个愚蠢的解决方法了。

无论如何,这里的问题是:当收到或更改新的 属性 时,是否有更好的选项来更新状态?

/*...*/
/**
 * To be called before mounted and before updating props
 * @param props
 */
prepareComponentState: function (props) {
    var usedProps = props || this.props;

    //set data on state/template
    var currentResponses = this.state.candidatesResponses.filter(function (elem) {
        return elem.questionId === usedProps.currentQuestion.id;
    });
    this.setState({
        currentResponses: currentResponses,
        activeAnswer: null
    });
},
componentWillMount: function () {
    this.prepareComponentState();
},
componentWillReceiveProps: function (nextProps) {
    this.prepareComponentState(nextProps);
},
/*...*/

我觉得有点傻,我想我失去了一些东西...... 我想还有另一种解决方案可以解决这个问题。

是的,我已经知道了: https://facebook.github.io/react/tips/props-in-getInitialState-as-anti-pattern.html

我发现这种模式通常不是很有必要。 在一般情况下(并非总是如此),我发现根据更改的属性设置状态有点反模式;相反,只需在渲染时导出必要的 local 状态。

render: function() {
  var currentResponses = this.state.candidatesResponses.filter(function (elem) {
    return elem.questionId === this.props.currentQuestion.id;
  });

  return ...; // use currentResponses instead of this.state.currentResponses
}

然而,在某些情况下,缓存这些数据是有意义的(例如,可能计算它的成本非常高),或者出于其他原因,您只需要知道 props 何时 set/changed。在那种情况下,我基本上会使用您在问题中所写的模式。

如果你真的不喜欢输入它,你可以将这个新方法形式化为一个 mixin。例如:

var PropsSetOrChangeMixin = {
  componentWillMount: function() {
    this.onPropsSetOrChange(this.props);
  },

  componentWillReceiveProps: function(nextProps) {
    this.onPropsSetOrChange(nextProps);
  }
};

React.createClass({
  mixins: [PropsSetOrChangeMixin],

  onPropsSetOrChange: function(props) {
    var currentResponses = this.state.candidatesResponses.filter(function (elem) {
        return elem.questionId === props.currentQuestion.id;
    });

    this.setState({
      currentResponses: currentResponses,
      activeAnswer: null
    });
  },

  // ...
});

当然,如果您使用基于 class 的 React 组件,您需要找到一些替代解决方案(例如继承或自定义 JS 混合),因为它们没有 React 风格立即混合。

(就其价值而言,我认为使用显式方法的代码更清晰;我可能会这样写:)

componentWillMount: function () {
  this.prepareComponentState(this.props);
},

componentWillReceiveProps: function (nextProps) {
  this.prepareComponentState(nextProps);
},

prepareComponentState: function (props) {
  //set data on state/template
  var currentResponses = this.state.candidatesResponses.filter(function (elem) {
    return elem.questionId === props.currentQuestion.id;
  });
  this.setState({
    currentResponses: currentResponses,
    activeAnswer: null
  });
},