React之setState的正确打开方式

React官方文档中提到:html

NEVER mutate this.state directly, as calling setState() afterwards may replace the mutation you made. Treat this.state as if it were immutable.react

setState() does not immediately mutate this.state but creates a pending state transition. Accessing this.state after calling this method can potentially return the existing value.git

There is no guarantee of synchronous operation of calls to setState and calls may be batched for performance gains. setState() will always trigger a re-render unless conditional rendering logic is implemented in shouldComponentUpdate().github

If mutable objects are being used and the logic cannot be implemented in shouldComponentUpdate(), calling setState() only when the new state differs from the previous state will avoid unnecessary re-renders.less

下面的代码分别是官方推荐和不推荐的两种改变state的方式:异步

class Dog extends Component {
    constructor(props) {
        super(props)
        this.state = {
            color: 'white',
            age: 7,
            son: {
              color: 'gray',
              age: 1
            }
        }
    }
    
    brushHair() {
      //right
      setState({color: 'white'})
      
      //wrong
      this.state.color = 'black';
    }
}

但你会发如今实践中即使使用第二种写法也不会报任何错误,甚至还能获得预期结果,那么为何这种方式会被诟病呢?下面我谈谈本身的理解:函数

  1. React中state发生变化,组件就会更新。setState()被设计为异步的,其目的在于在某些状况下(如一次onClick中)延缓并将屡次更新合并为一次从而优化组件性能,若是像第二种写法那样直接改变state的值,这种优化也就不存在了;性能

  2. 执行setState会按照React设计的执行顺序,调用其内部的各类函数,若是直接改变state,这些本应被调用的函数没有执行,可能会致使奇奇怪怪的错误;优化

  3. 由于setState()是异步的,因此上面的代码最终color的值多是white,显然不符合正常的思惟逻辑;this

有时候咱们但愿在setState以后当即使用state的值,有两种方法能够实现这个需求:
方法一:

setState({ color: 'red' }, () => console.log(this.state.color));

即向setState传入一个回调函数,这个函数会在state发生变化以后被调用。

方法二:

setState({ age: 18 });
setState((prevState, props) => ({
  age: ++prevState.age
}))

setState的第一个参数还能够是一个函数,这个函数的返回值就是要merge的state,区别在于这个setState会在以前的setState执行完毕后再执行,因此prevState是最新的state。

另外,当更新state的部分属性时,其余属性是不会受影响的,本质上是Object.assign({}, state, partialState),但仅限于第一层结构,若是像下面这样

brushSonHair() {
    setState({
        son: {
            color: 'black'
        }
    })
}

上面的方法中setState改变的时第二层的属性值(son中的color),第一层的属性值(color age)不会受到影响,但son中的age属性就会丢失(能够理解为改变了son)。

相关文章
相关标签/搜索