React之setState

1,814 阅读2分钟

使用过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只增加了1
function 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会合并

前面我们了解到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

参考:setState:这个API设计到底怎么样