一.为什么使用setState?

1)作用

  为了管理和维护React中的状态,除了Redux转态管理器,React内部提供了setState来进行组件内的状态管理。

2)基本使用

  a.向setState中传入一个对象对已有的state进行更改

  b.setState可以接受一个函数作为参数,这个函数返回也是一个对象,同上,但是该函数参数为state的前一个状态以及props

      c.setState可以接受两个参数,第一个可以是a,b两种情况。第二个参数是回调函数,始终是执行完setState后再执行回调函数。

 

/*
    void setState (
      function|object nextState,
      [function callback]
   )
   */

 

 

class Home extend React.component{
   constructor(props){
       super(props);
       this.state{
          number:1,
      }  
   }
//a
    changeA=()=>{
        this.setState({
            number:2,
      })  
   }
  //b
   changeB=()=>{
        this.setState((preState,props)=>{
          return ({
             number:preState.number+1,      
         })
      })  
   }
  //c
  changeC=()=>{
        this.setState({
          number:3,
      },callback=>{
         console.log('执行完setState后,再执行这个回调函数')
   })  
   }
}

二.setState到底干了什么?  

1)执行setState()后做了什么?

  setState通过一个队列机制实现state的更新,当执行setState()的时候,会将需要更新的state合并之后放入状态队列,而不会立即更新this.state(可以和浏览器的事件队列类比)。如果我们不使用setState而是使用this.state.key来修改,会修改但是将不会触发组件的re-render(不渲染)。

2)注意:

  a.不要使用this.state直接修改state,(因为修改后不render,导致显示的内容和实际存在的state不一致),用setState代替;

  b.state更新可能是异步的。不要用this.setState({this.state.number+this.props.xxx}),由于异步可能获取不到你想要的内容。此时需要使用上面所说第一个问题基本使用的b方法。

  c.state更新会被合并。当你调用 setState(), React 将合并你提供的对象到当前的状态中。所以当State是一个多键值的结构时,可以单独更新其中的一个,此时会进行“差分”更新,不会影响其他的属性值。

三.setState是同步的还是异步的?

  由 React 控制的事件处理过程 setState 不会同步更新 this.state!
      也就是说,在 React 控制之外的情况, setState 会同步更新 this.state!(如下边例子setTimeOut()函数内)

但大部份的使用情况下,我们都是使用了 React 库中的表单组件,例如 select、input、button 等等,它们都是 React 库中人造的组件与事件,是处于 React 库的控制之下,比如组件原生 onClick 都是经过 React 包装。在这个情况下,setState 就会以异步的方式执行。

 

class page extends Component {

    state = {
        name: 'xxx',
        age: 20,
    }

    onClickDiv = () => {
        this.setState((prevState, props) => {
            console.log('11-------', prevState);
            return ({
                name: 'xxx11',
            })
        })
        this.setState((prevState, props) => {
            console.log('22-------', prevState);
            return ({
                name: 'xxx22',
                age: 30,
            })
        })
        console.log('异步还是同步1111????');
        setTimeout(() => {
            this.setState({ name: 'xxx33' })
            console.log('异步还是同步2222????');
            this.setState((prevState, props) => {
                console.log('33-------', prevState);
                return ({
                    name: 'xxx44',
                })
            })
            console.log('异步还是同步3333????', this.state.name);
            this.setState((prevState, props) => {
                console.log('44-------', prevState);
                return ({
                    name: 'xxxx55',
                })
            })
            console.log('异步还是同步4444????', this.state.name);
            this.setState({ name: 'xxxx66' }, () => {
                console.log('完成');
            })
            console.log('异步还是同步5555????', this.state.name);
            this.state.name = 'xxxx77'
        }, 2000);
    }

    render() {
        const { name, age } = this.state
        console.log(name, age);
        return (
            <div onClick={() => this.onClickDiv()}>
                {name}nihao{age}
                <div className={styles.contentMap}>
                    <div id="map" className={styles.map}></div>
                </div>
            </div>
        )
    }
}


/*
====================点击第1次-----setTimeOut外表现异步,内表现同步=============
异步还是同步1111????
11------- {name: "999888", age: 20}
22------- {name: "xxx11", age: 20}
xxx22 30
xxx33 30
异步还是同步2222????
33------- {name: "xxx33", age: 30}
xxx44 30
异步还是同步3333???? xxx44
44------- {name: "xxx44", age: 30}
xxxx55 30
异步还是同步4444???? xxxx55
xxxx66 30
完成
异步还是同步5555???? xxxx66

====================点击第2次--this.state能修改但未render=============
异步还是同步1111????
11------- {name: "xxxx77", age: 30}
...
*/