我已经用React编程了一段时间了,但是我从未遇到过这个烦人的问题,在componentWillReceiveProps
中的setState()
执行之前,我的一个组件componentDidMount
被触发了。这会在我的应用程序中引起几个问题。
我从prop收到一个变量this.props.flag
,该变量将存储在组件状态下:
componentDidMount() {
if (!_.isEmpty(this.props.flag)) {
console.log('Flag Did:', this.props.flag);
this.setState({
flag: this.props.flag
},
() => doSomething()
);
}
在我的componentWillReceiveProps
方法中,变量this.state.flag
将被替换,即使它为空或与this.props.flag
的值不同(使用lodash进行检查)库):
componentWillReceiveProps(nextProps) {
const { flag } = this.state;
console.log('Flag Will:', !_.isEqual(flag, nextProps.flag), flag, nextProps.flag);
if (!_.isEmpty(nextProps.flag) && !_.isEqual(flag, nextProps.flag)) {
this.setState({
flag: nextProps.flag,
},
() => doSomething()
);
}
}
假设在这种情况下,道具flag
始终具有相同的值,并且this.state.flag
被初始化为undefined
。当我检查控制台日志时,看到以下结果:
Flag Did: true
Flag Will: true undefined true
因此,当代码输入componentWillReceiveProps
时,this.state.flag
的值仍为undefined
,这意味着setState
中的componentDidMount
尚未设置。
这与React生命周期不一致,或者我缺少什么吗?我该如何避免这种行为?
答案 0 :(得分:1)
ComponentWillReceiveProps()
。由于Javascript是同步的,因此有时您可能需要验证道具来保存应用程序崩溃。我尚未完全了解您的应用程序的上下文,但是您可以做的是:
componentWillReceiveProps(nextProps) {
const { flag } = this.state;
if(!flag){
return;,
}
console.log('Flag Will:', !_.isEqual(flag, nextProps.flag), flag, nextProps.flag);
if (!_.isEmpty(nextProps.flag) && !_.isEqual(flag, nextProps.flag)) {
this.setState({
flag: nextProps.flag,
},
() => doSomething()
);
}
}
如果状态未定义,则可以返回。父级重新渲染后将再次调用它。但这可能不是用例。
无论如何,您都应该研究this:
但是我可以想到至少有1种(可能是理论上的)情形,其顺序将被反转:
组件接收道具,并开始渲染。而组件是 渲染,但尚未完成渲染,组件收到新的 道具。触发componentWillReceiveProps(),(但componentDidMount 还没有被解雇)所有子代和组件本身都拥有 完成渲染后,componentDidMount()将触发。所以 componentDidMount()不是初始化的好地方 像您的{foo:'bar'}这样的组件变量。 componentWillMount() 会是一个更好的生命周期事件。但是,我不鼓励任何使用 反应组件内部组件范围内的变量,并坚持 设计原则:
所有组件变量都应处于状态或道具(并且 不可变的),所有其他变量都受生命周期方法约束(并且 不超过此范围)
答案 1 :(得分:0)
根据用户JJJ的建议,鉴于setState
的异步性质,if (!_.isEmpty(nextProps.flag) && !_.isEqual(flag, nextProps.flag))
中的检查componentWillReceiveProps
在setState
内部的componentDidMount
执行{{ 1}}。操作顺序为:
flag: this.props.flag
。componentDidMount
尚未发生)。flag: this.props.flag
,componentDidMount
中的setState
是
仍在执行中(componentDidMount
尚未发生)。flag: this.props.flag
。componentWillReceiveProps
if
(!_.isEmpty(nextProps.flag) && !_.isEqual(flag, nextProps.flag))
已执行(componentWillReceiveProps
仍在
未定义)。 this.state.flag
的执行
setState
并设置componentDidMount
并执行
flag: this.props.flag
。doSomething()
的执行
setState
并设置componentWillMount
并执行
flag: nextProps.flag
。鉴于doSomething()
的异步特性,6和7可以并行执行,因此我们不知道哪个将首先完成其执行。在这种情况下,setState
被调用至少两次,而必须被调用一次。
为了解决这些问题,我以这种方式更改了代码:
DoSomething()
这样,我将道具的新版本(componentWillReceiveProps(nextProps) {
if (!_.isEmpty(nextProps.flag) && !_.isEqual(this.props.flag, nextProps.flag)) {
this.setState({
flag: nextProps.flag,
},
() => doSomething()
);
}
}
)与旧版本(nextProps
)进行比较,而无需等待this.props
值存储在组件状态中。