ReactJS setState 详解

11,033 阅读2分钟
setState(nextState, callback)

这是UI更新最常用的方法,合并新的state到现有的state。

常规方式

nextState可以为一个对象,包含0个或多个要更新的key。最简单的用法为:

this.setState({
  key1: value1, 
  key2: value2
});

这种方式能应付大部分的应用场景,但是看看下面这种情况:

this.setState({
  count: this.state.count + 1
});
this.setState({
  count: this.state.count + 1
});

最后得到的count却是不可控的。因为setState不会立即改变this.state,而是挂起状态转换,调用setState方法后立即访问this.state可能得到的是旧的值。

setState方法不会阻塞state更新完毕

第二个setState可能还没等待第一次的state更新完毕就开始执行了,所以最后count可能只加了1。

这时setState的第二个参数就派上用场了,第二个参数是state更新完毕的回调函数

this.setState({
  count: this.state.count + 1
}, () => {
  this.setState({
    count: this.state.count + 1
  });
});

不过看起来很怪,es6中可以使用Promise更优雅的使用这个函数,封装一下setState

function setStateAsync(nextState){
  return new Promise(resolve => {
    this.setState(nextState, resolve);
  });
}

上面的例子就可以这样写

async func() {
  ...
  await this.setStateAsync({count: this.state.count + 1});
  await this.setStateAsync({count: this.state.count + 1});
}

顺眼多了。

函数方式

nextState也可以是一个function,称为状态计算函数,结构为function(state, props) => newState。这个函数会将每次更新加入队列中,执行时通过当前的stateprops来获取新的state。那么上面的例子就可以这样写

this.setState((state, props) => {
  return {count: state.count + 1};
});
this.setState((state, props) => {
  return {count: state.count + 1};
});

每次更新时都会提取出当前的state,进行运算得到新的state,就保证了数据的同步更新。

控制渲染

默认调用setState都会重新渲染视图,但是通过shouldComponentUpdate()函数返回false来避免重新渲染。

如果可变对象无法在shouldComponentUpdate()函数中实现条件渲染,则需要控制newStateprevState不同时才调用setState来避免不必要的重新渲染。