og

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---

Article at   2020/05/18 08:06  Published  code  Category,viewed  199  times

Relevant tags:    React 

Address:   https://www.kedong.me/article/11

Copyright Notice: Freely reproduced for non-commercial use