React.js向state的omens数组新增值后alert仅显示旧数据问题
问题定位
开发React.js简易占卜类应用时,未使用常规字符串列表存储占卜内容,改为存储包含独立id、omen字段的对象数组。当前异常为:点击新增占卜条目后,预期弹出alert展示state中omens的完整最新内容,但弹窗仅能展示更新前的旧值,未包含刚添加的新条目,控制台同位置打印的omens数据也存在同样的滞后问题,导师的相似实现无该异常。
问题根因
该异常是React类组件中setState的异步更新机制导致的:
- 为了实现性能优化,React会对同一事件回调内的多次
setState调用做批处理,不会在调用setState的同步执行过程中立刻修改组件实例上的this.state值。 - 你在
handleAddOmen中的执行顺序为:先基于原有omens数组拼接生成包含新条目的本地数组,随即调用setState提交状态更新,紧接着在同一段同步代码中直接读取this.state.omens用于控制台打印、拼接alert弹窗内容。此时状态更新尚未完成提交,读取到的依然是更新前的state快照,因此获取不到刚添加的新条目。
修正方法
有两种合规的实现方式可以解决该问题:
- 直接用本地已经生成的、包含新条目的omens数组拼接弹窗内容,无需等待state更新。该数组本身已经包含所有新旧占卜条目,不需要依赖state的返回值。
- 若必须要拿到state更新后的最新值做弹窗展示,可以利用
setState的第二参数——状态更新完成的回调函数。该回调会在React完成状态合并、组件触发重渲染后执行,此时读取this.state拿到的就是包含新条目的最新值。
参考修正代码
handleAddOmen = () => { if (this.state.value === "") { return alert("Enter some omen!"); } const newOmenList = this.state.omens.concat({ id: this.state.omens.length + 1, omen: this.state.value, }); this.setState({ omens: newOmenList, value: "", }, () => { // 该回调内的this.state为更新完成后的最新值 console.log(this.state.omens); alert( `Omen added. Actual omens: ${this.state.omens.map( (omen) => omen.omen )}` ); }); };
补充说明:导师的实现未出现该问题,通常是因为他的弹窗逻辑没有放在setState调用后的同步代码块中读取state,要么是直接使用本地新数组拼接弹窗内容,要么是通过setState的更新回调拿到了最新的state值。
内容的提问来源于stack exchange,提问作者Paweł Zajączkowski
相关产品推荐
相关产品推荐

