我遇到了有关基于属性的状态的问题。
我有一个组件父组件,它创建一个将属性传递给子组件的组件。子组件根据收到的属性做出反应。据我所知,在React中,更改组件状态的“唯一”正确方法是使用componentWillMount或componentDidMount和componentWillReceiveProps函数(还有其他功能,但让我们关注这些功能,因为getInitialState仅执行一次)。
如果我从父级收到一个新属性,并且想更改状态,则仅执行componentWillReceiveProps函数,并允许我执行setState。渲染不允许setStatus。
如果我想在开始接收新属性时设置状态,该怎么办?所以我必须在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
我发现这种模式通常不是非常必要。 在一般情况下 (并非总是如此),我发现基于更改后的属性设置状态有点反模式。相反,只需在渲染时导出必要的 局部 状态即可。
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 }
但是,在某些情况下,缓存此数据是有意义的(例如,计算它的成本过高),或者您只需要知道何时出于其他原因设置/更改道具。在这种情况下,我基本上会使用您在问题中所写的模式。
如果您 真的 不喜欢将其键入,则可以将此新方法形式化为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的React组件,则需要找到一些替代解决方案(例如,继承或自定义JS混合),因为它们目前尚无法获得React样式的混合。
class
(对于它的价值,我认为使用显式方法可以使代码更加清晰;我可能会这样写:)
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 }); },