为何ReactJS按官方推荐方式更新state不生效?
错误根因
你按参考写的函数式setState不生效,本质是写法本身不符合规范,并没有正确使用prevState:
- 你在返回的对象里写了
prevState.selectedRatingIndex = val,这行是直接修改状态快照prevState的属性,属于变相的直接修改状态,不是返回新的状态值。 - 第二个
setState计算isSelected时,用了闭包里的this.state.isSelected而不是入参的prevState.isSelected,在函数式更新场景下会拿到旧的状态值,导致逻辑错误。
而你后来能跑通的写法,逻辑是「先直接给this.state的属性赋值(这就是触发Do not mutate state directly警告的原因),再把赋值结果传给setState」,只是碰巧能运行,完全违背React的状态设计原则,异步/批量更新场景下一定会出bug。
正确实现
先记两个核心规则:
prevState是上一次状态的不可变快照,绝对不能直接修改它的属性,只能基于它计算新的状态值。- 多个关联状态的更新可以合并到同一个
setState返回,不需要拆分多个调用。
针对你的场景,正确写法如下:
onClick={() => { this.setState(prevState => ({ // 直接返回新的属性值,不要对prevState做赋值操作 selectedRatingIndex: val, // 基于prevState计算新值,不要引用this.state isSelected: !prevState.isSelected })); // 其他业务逻辑 }}
如果需要在状态更新后拿到最新值做后续操作,用setState的回调参数,不要直接读取this.state:
onClick={() => { this.setState(prevState => ({ selectedRatingIndex: val, isSelected: !prevState.isSelected }), () => { // 这里能拿到更新后的最新状态,后续逻辑写在这里 console.log(this.state.selectedRatingIndex, this.state.isSelected) }); }}
为什么你之前的“能跑”写法是错的
你写的selectedRatingIndex: (this.state.selectedRatingIndex = val),执行顺序是:
- 先执行括号内的赋值语句:直接把
val写到this.state.selectedRatingIndex上(直接修改状态,触发警告) - 再把赋值语句的返回值
val作为对象属性传给setState
相当于绕了个弯先改了状态,再通知React触发更新,虽然同步场景下碰巧能看到效果,但React的批量更新、异步更新机制下,一定会出现状态不一致的问题。
内容的提问来源于stack exchange,提问作者Masi Boo
相关产品推荐
相关产品推荐

