使用过React的用户都知道setState是一个管理state的重要方法,下面简单介绍下这个API。
setState不会立即改变组件中state的值
我们知道,this.state是只读的,更新状态不能直接修改,而是通过this.setState方法。这是为什么呢?this.state只是一个对象,我们修改它的值是没有意义的。仔细想一想,我们之所以要修改state,无非是为了改变页面的渲染状态;所以React设计setState方法就是为了重新渲染页面。
我们可以在setState之后打印一下this.state的值,会发现它并没有改变,还是之前的值。如果我们需要在短时间内多次setState,并且每次setState的值跟之前的状态有关,我们就需要使用函数作为setState的参数了,这个函数参数接收两个参数(当前的state和当前的props)。举个例子:
// 可能最终产生的结果是this.state.value只增加了1function test1() { this.setState({ value: this.state.value + 1 }); this.setState({ value: this.state.value + 1 }); this.setState({ value: this.state.value + 1 });}// 换种写法,结果就如我们所意了function test2() { this.setState((state, props) => ({ value: state.value + 1 })); this.setState((state, props) => ({ value: state.value + 1 })); this.setState((state, props) => ({ value: state.value + 1 }));}复制代码
因为使用函数式setState,React会保证每次调用函数时,state都已经合并了之前的状态修改结果。
setState还有第二个参数callback,所以下面这种写法也是可以的:
this.setState({ value: this.state.value + 1 }, (val) => { this.setState({ value: this.state.value + 1 }, () => { this.setState({ value: this.state.vavlue + 1 }); });});复制代码
我个人还是比较倾向于函数式setState的写法。
貌似有时候setState也会同步更新state,比如使用setTimeout/setInterval或者addEventListener处理事件。具体参考
多次setState会合并
前面我们了解到setState并不会立即改变state的值,而是将其放到一个任务队列里,最终将多个setState合并,一次性更新页面。所以我们可以在代码里多次调用setState,每次只需要关注当前修改的字段即可。
另外,需要注意的是,setState触发页面重新渲染需要经过以下生命周期:
- shouldComponentUpdate
- componentWillUpdate
- render
- componentDidUpdate
经过测试,其实state的值只有在render的时候才真正被修改了,在shouldComponentUpdate和componentWillUpdate时还是之前的值。测试结果如下:
// shouldComponentUpdate: 0// componentWillUpdate: 0// render: 1// componentDidUpdate: 1// shouldComponentUpdate: 1// componentWillUpdate: 1// render: 2// componentDidUpdate: 2// shouldComponentUpdate: 2// componentWillUpdate: 2// render: 3// componentDidUpdate: 3复制代码
参考: