react setState 的坑
问题
setState
是更新 state
的 API,进而会引发组件的重新渲染。然而在使用过程中发现有些坑(参见 react 正确使用状态):
setState(obj)
一般情况下不会立即更新state
的值;- 同一 cycle 的多次
setState
调用可能会合并(性能考虑)
对于第一点,引用下边的例子:
1 | function incrementMultiple() { |
代码运行时,虽然是对 state
加了三次,但是每次加操作都是针对初始的 state
,所以最终相当于仅加了一次。即上述代码等同于下边的代码:
1 | Object.assign( |
为什么
从 react 生命周期看 setState 生效时间
要理解其原因,我们要先看一下 react 生命周期:
setState
引起状态更新涉及四个函数:
- shouldComponentUpdate(默认 true)
- componentWillUpdate
- render
- componentDidUpdate
但直到 render
被调用时,state
才被更新。
(如果 shouldComponentUpdate
返回 false
,则 render
不会被执行,但是 state
会被更新)
因此多次调用 setState
时,不能依靠 this.state
来计算下一个 state
的值,因为 this.state
一直没更新。
setState() does not always immediately update the component. It may batch or defer the update until later. This makes reading this.state right after calling setState() a potential pitfall.
但是可以使用 setState(func) api 来解决上述问题
setState api
setState
api 如下:
1 | setState(updater[, callback]) |
其中,callback
是在 setState
完成且组件 re-render 完成后执行(一般建议用 componentDidUpdate
来实现类似逻辑)。
而 updater
可以是:
- obj:异步将 obj shallow merge 到旧
state
,构建新state
- func:形式如下:
1 | (prevState, props) => stateChange |
解决方案
上述例子做如下修改即可实现真正的累加:
1 | function increment(state) { |