React setState

Snipaste_20200518_160614.jpg

setState()更新状态的2种写法

  • setState(updater, [callback])

updater为返回stateChange对象的函数: (state, props) => stateChange 接收的state和props被保证为最新的

  • setState(stateChange, [callback])

stateChange为对象, callback是可选的回调函数, 在状态更新且界面更新后才执行

下面是setstate简单的代码

          
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
class Demo extends React.Component { static defaultProps = { name: "defaultProps" } state = { count: 1, } // count数量加1 test1 = () => { /* this.setState({ count: this.state.count + 1 }) */ this.setState((state, props) => { console.log(props); return { count: state.count + 1 } }) // 调用函数形式的setState()更新状态 console.log('setState()之后,this.state.count值:', this.state.count) // ? } // count数量变为3 test2 = () => { this.setState({ count: 3 }, ) // 调用对象形式的setState()更新状态 console.log('调用对象形式的setState()之后,this.state.count值:', this.state.count) } // 带回调的setState() test3 = () => { this.setState( state => ({ count: state.count + 1 }), () => {// 什么时候执行? 状态数据更新且界面更新后立即执行 console.log('在callback中,this.state.count值:', this.state.count) } ) } render() { console.log(' render()后,this.state.count值:', this.state.count) return ( <div> <h1>Demo组件: {this.state.count}</h1> <button onClick={this.test1}>调用函数形式的setState()更新状态+1</button>&nbsp;&nbsp; <button onClick={this.test2}>调用对象形式的setState()更新状态使count变3</button>&nbsp;&nbsp; <button onClick={this.test3}>'在callback中', this.state.count的值</button>&nbsp;&nbsp; </div> ) } } export default Demo

上面这段代码简述了this.state的详细用法,在callback中,显然能拿到最新的state的值,callback回调函数应该在render后执行。

根据上述console.log打印出的值,似乎能看出setState是异步执行的,不过其实并不是这样的,我们来看下面的代码。

          
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
class Demo1 extends React.Component { constructor(props){ super(props) this.state = { count: 0, } this.button=React.createRef() } /* react生命周期勾子中, setState()是异步更新状态 */ componentDidMount() { console.log('setState()之前', this.state.count) this.setState(state => ({ count: state.count + 1 })) console.log('setState()之后', this.state.count) } /* react事件监听回调中, setState()是异步更新状态 */ update1 = () => { console.log('setState()之前', this.state.count) this.setState(state => ({ count: state.count + 1 })) console.log('setState()之后', this.state.count) } /* 定时器回调 / 原生事件监听回调 / promise回调 setState()是同步更新状态 */ update2 = () => { setTimeout(() => { console.log('setState()之前', this.state.count) this.setState(state => ({ count: state.count + 1 })) console.log('setState()之后', this.state.count) }, 0); } update3 = () => { this.button.current.onclick = () => { console.log('setState()之前', this.state.count) this.setState(state => ({ count: state.count + 1 })) console.log('setState()之后', this.state.count) } } update4 = () => { Promise.resolve().then(() => { console.log('setState()之前', this.state.count) this.setState(state => ({ count: state.count + 1 })) console.log('setState()之后', this.state.count) }) } render() { const { count } = this.state console.log('render()', count) return ( <div> <h2>{count}</h2> <button onClick={this.update1}>react事件中更新</button> --- <button onClick={this.update2}>定时器事件中更新</button> &nbsp; <button ref={this.button} onClick={this.update3}>原生事件中更新</button> &nbsp; <button onClick={this.update4}>promise中更新</button> --- </div> ) } } export default Demo1

总结 异步执行 在react控制的回调函数中: 生命周期勾子 / react事件监听回调

同步执行 非react控制的异步回调函数中: 定时器回调 / 原生事件监听回调 / promise回调 /...

接着,我们再来看看用函数形式和对象形式的区别,我们用两次调用setState来对比

          
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
class Demo2 extends React.Component { constructor(props){ super(props) this.state = { count: 0, } } /* 2次调用函数方式的setState() */ update1 = () => { console.log('setState()之前', this.state.count) this.setState(state => ({ count: state.count + 1 })) console.log('setState()之后', this.state.count) console.log('setState()2之前', this.state.count) this.setState(state => ({ count: state.count + 1 })) console.log('setState()2之后', this.state.count) } /* 2次调用对象方式的setState() */ update2 = () => { console.log('setState()之前', this.state.count) this.setState({ count: this.state.count + 1 }) console.log('setState()之后', this.state.count) console.log('setState()2之前', this.state.count) this.setState({ count: this.state.count + 0 }) console.log('setState()2之后', this.state.count) } /* 先对象方式后函数方式的setState() */ update3 = () => { console.log('setState()之前', this.state.count) this.setState({ count: this.state.count + 1 }) console.log('setState()之后', this.state.count) console.log('setState2()之前', this.state.count) this.setState(state => ({ count: state.count + 1 })) console.log('setState()2之后', this.state.count) } /* 先函数方式后对象方式的setState() */ update4 = () => { console.log('setState()之前', this.state.count) this.setState(state => ({ count: state.count + 1 })) console.log('setState()之后', this.state.count) console.log('setState()2之前', this.state.count) this.setState({ count: this.state.count + 1 }) console.log('setState()2之后', this.state.count) } render() { const { count } = this.state console.log('render()', count) return ( <div> <h2>{count}</h2> <button onClick={this.update1}>2次调用函数方式的setState()</button> &nbsp; <button onClick={this.update2}>2次调用对象方式的setState()</button> &nbsp; <button onClick={this.update3}>先对象方式后函数方式的setState()</button> &nbsp; <button onClick={this.update4}>先函数方式后对象方式的setState()</button> &nbsp; </div> ) } } export default Demo2

很明显,

对象方式,合并更新一次状态,只调用最后一次

函数方式,会更新多次状态,但同样render的运行还是一次。

总结:

  1. 对象方式是函数方式的简写方式
  2. 如果新状态不依赖于原状态 ===> 使用对象方式 如果新状态依赖于原状态 ===> 使用函数方式
  3. 如果需要在setState()后获取最新的状态数据, 在第二个callback函数中读取
---end---
(完)
恶魔在人间
费县515案件
2020我在干啥?
误删照片引发的随笔
2022年终总结
我的2022
My Weight Loss Experience
Lose weight again over the next three months
2020年终总结
再见2020,我要去拥抱2021啦!Happy new year!
React Refs的使用
Refs 提供了一种方式,允许我们访问 DOM 节点或在 render 方法中创建的 React 元素。
等待你的评论