state

理解

  1. state是组件对象最重要的属性, 值是对象(可以包含多个key-value的组合)
  2. 组件被称为”状态机”, 通过更新组件的state来更新对应的页面显示(重新渲染组件)

    注意事项

  3. 组件中render方法中的this为组件实例对象

  4. 组件自定义的方法中this为undefined,如何解决?
    a) 强制绑定this: 通过函数对象的bind()
    b) 箭头函数
  5. 状态数据,不能直接修改或更新
  6. this.state是纯js对象,在vue中,data属性是利用 Object.defineProperty 处理过的,更改data的 数据的时候会触发数据的 getter 和 setter ,但是React中没有做这样的处理,如果直接更改的话, react是无法得知的,所以,需要使用特殊的更改状态的方法 setState 。

    复杂形式代码

    1. class Weather extends React.Component{
    2. //构造器调用几次? ———— 1次
    3. constructor(props){
    4. console.log('constructor');
    5. super(props)
    6. //初始化状态
    7. this.state = {isHot:false,wind:'微风'}
    8. }
    9. //render调用几次? ———— 1+n次 1是初始化的那次 n是状态更新的次数,但是一次性调用多次setData,render只更新一次
    10. render(){
    11. console.log('render');
    12. //读取状态
    13. const {isHot,wind} = this.state
    14. //解决changeWeather中this指向问题
    15. return <h1 onClick={this.changeWeather.bind(this)}>今天天气很{isHot ? '炎热' : '凉爽'},{wind}</h1>
    16. }
    17. //changeWeather调用几次? ———— 点几次调几次
    18. changeWeather(){
    19. //changeWeather放在哪里? ———— Weather的原型对象上,供实例使用
    20. //由于changeWeather是作为onClick的回调,所以不是通过实例调用的,是直接调用
    21. //类中的方法默认开启了局部的严格模式,所以changeWeather中的this为undefined
    22. console.log('changeWeather');
    23. //获取原来的isHot值
    24. const isHot = this.state.isHot
    25. //严重注意:状态必须通过setState进行更新,且更新是一种合并,不是替换。
    26. this.setState({isHot:!isHot})
    27. console.log(this);
    28. //严重注意:状态(state)不可直接更改,下面这行就是直接更改!!!
    29. //this.state.isHot = !isHot //这是错误的写法
    30. }
    31. }
    32. //2.渲染组件到页面
    33. ReactDOM.render(<Weather/>,document.getElementById('test'))

    简写形式代码

    1. //1.创建组件
    2. class Weather extends React.Component{
    3. //初始化状态
    4. state = {isHot:false,wind:'微风'}
    5. render(){
    6. const {isHot,wind} = this.state
    7. return <h1 onClick={this.changeWeather.bind(this)}>今天天气很{isHot ? '炎热' : '凉爽'},{wind}</h1>
    8. }
    9. //自定义方法————要用赋值语句的形式+箭头函数
    10. changeWeather = ()=>{
    11. const isHot = this.state.isHot
    12. this.setState({isHot:!isHot})
    13. }
    14. }
    15. //2.渲染组件到页面
    16. ReactDOM.render(<Weather/>,document.getElementById('test'))

    setState(异步|同步)

    setState异步|同步情况

  7. setState处在同步的逻辑中, 异步更新状态,更新真实dom

  8. setState处在异步的逻辑中, 同步更新状态,同步更新真实dom ```javascript

    //count =1 //同步的逻辑中, 异步更新状态,更新真实dom handleAdd1 = ()=>{

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

    console.log(this.state.count)//1

    this.setState({
        count:this.state.count+1
    })
  console.log(this.state.count)//1
}

handleAdd2 = ()=>{
    //异步的逻辑中,  同步更新状态,同步更新真实dom
    setTimeout(()=>{
        this.setState({
            count:this.state.count+1
        })

        console.log(this.state.count)//2

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

        console.log(this.state.count)//3
    },0)

}
<a name="AwmTt"></a>
## setState更新状态的2种写法
(1). setState(stateChange, [callback])------对象式的setState
        1.stateChange为状态改变对象(该对象可以体现出状态的更改)
        2.callback是可选的回调函数, 它在状态更新完毕、界面也更新后(render调用后)才被调用

(2). setState(updater, [callback])------函数式的setState
        1.updater为返回stateChange对象的函数。
        2.updater可以接收到state和props。
        4.callback是可选的回调函数, 它在状态更新、界面也更新后(render调用后)才被调用。

总结: 1.对象式的setState是函数式的setState的简写方式(语法糖) 2.使用原则: (1).如果新状态不依赖于原状态 ===> 使用对象方式 (2).如果新状态依赖于原状态 ===> 使用函数方式 (3).如果需要在setState()执行后获取最新的状态数据, 要在第二个callback函数中读取


---

方式一 会因为异步更新导致连续调用的结果如下
```jsx
//设置count = 1
this.setState({
  count: this.state.count + 1
})
console.log('count:', this.state.count) // 1

this.setState({
  count: this.state.count + 1 // 1 + 1
})
console.log('count:', this.state.count) // 1

推荐方式二:这样连续调用this.setState 不会因为异步导致后者无法获取最新内容

// 方式一 : 对象形式,其实是方式二的语法糖
this.setState({name:'Change'});

// 方式二 : 函数形式
this.setState((state, props) => ({name:'Change'}));

// 方式一和二 都可以接受一个回调 用于state被修改后
this.setState({name:'Change'},()=>{
    console.log('我被修改啦');
})

修改引用类型数据

比如数组,使用使用push,改变了数组但未实现响应式

hdClick(){
  //深或浅复制再set
  this.setState({
    arr:[...this.state.arr,'new']
  })

  //替换第一位
  let newArr = [...this.state.arr]
  newArr.splice(1,0,'new')
  this.setState({
    arr:newArr
  })
}