当属性更改并首次挂载 React 时更改状态 - 缺少功能?

IT技术 reactjs
2021-05-05 11:49:57

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

场景

我有一个组件父组件,它创建将一个属性传递给子组件。Child 组件根据收到的属性做出react。在 React 中,改变组件状态的“唯一”正确方法是使用 componentWillMount 或 componentDidMount 和 componentWillReceiveProps 函数,就我所见(除其他外,但让我们关注这些,因为 getInitialState 只执行一次)。

我的问题/问题

如果我从父级收到一个新属性并且我想更改状态,则只会执行函数 componentWillReceiveProps 并允许我执行 setState。Render 不允许设置状态。

如果我想在开始时设置状态和接收新属性的时间怎么办?所以我必须在 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

1个回答

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

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的时间。在这种情况下,我基本上会使用您在问题中编写的模式。

如果你真的不喜欢输入它,你可以将这个新方法形式化为 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 风格的混合。

(对于它的value,我认为使用显式方法的代码更清晰;我可能会这样写:)

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
  });
},