1、setState(updater, [callback])
------函数式的setState
updater
是一个返回stateChange
对象的函数(如下代码所示),它接收的state
和props
都保证为最新,updater
的返回值会与state
进行浅合并。
stateChange
为状态改变对象(该对象可以体现出状态的更改)。callback
是可选的回调函数, 它在状态更新完毕、界面也更新后(render()
调用后)才被调用。
(state, props) => stateChange
2、setState(stateChange, [callback])
------对象式的setState
stateChange
为状态改变对象(该对象可以体现出状态的更改),callback
是可选的回调函数, 它在状态更新完毕、界面也更新后(render()
调用后)才被调用。
总结:
1、对象式的setState
是函数式的setState
的简写方式(语法糖)
2、使用原则:
- 如果新状态不依赖于原状态 => 使用对象方式
- 如果新状态依赖于原状态 => 使用函数方式
- 如果需要在
setState()
执行后获取最新的状态数据, 要在第二个callback
函数中读取
3、关于setState()
更新状态的同步异步问题:
总的来说,可能是异步也可能是同步的。
-
在react控制的回调函数(生命周期回调、react事件监听回调等)中,它更新状态的操作就是异步的,异步更新后的状态数据在setState()
的callback
回调函数中;
-
在非react控制的回调函数(定时器、原生事件监听、promise回调等)中,它更新状态的操作就是同步的。
-
函数式的setState
如果多次调用:由于函数式的setState
内的updater
函数所接收的state
和props
都保证为最新,故它会更新多次状态,但是只调用一次render()
更新界面 ------ 状态更新没有合并,但界面更新合并了
-
对象式的setState
如果多次调用:只合并更新一次状态,只调用一次render()
更新界面 ------ 状态更新和界面更新都合并了
class Demo extends React.Component{
state = {
count: 0
}
componentDidMount(){
this.setState({count: this.state.count + 1}) // 3.1 -> count = 0 + 1
this.setState({count: this.state.count + 1}) // 3.2 -> count = 0 + 1
console.log(this.state.count) // 2 -> 0
this.setState(state => ({count: state.count + 1})) // 3.3 -> count = 1 + 1
this.setState(state => ({count: state.count + 1})) // 3.4 -> count = 2 + 1
console.log(this.state.count) // 3 -> 0
setTimeout(() => {
this.setState({count: this.state.count + 1}) // 8.1 -> count = 5 + 1
console.log('timeout', this.state.count) // 10 -> 6
this.setState({count: this.state.count + 1}) // 10.1 -> count = 6 + 1
console.log('timeout', this.state.count) // 12 -> 7
}, 0)
Promise.resolve().then(value => { //Promise先于setTimeout执行
this.setState({count: this.state.count + 1}) //调用setState后马上去render渲染,故4.1 -> count = 3 + 1
console.log('Promise', this.state.count) // 6 -> 4
this.setState({count: this.state.count + 1}) // 6.1 -> count = 4 + 1
console.log('Promise', this.state.count) // 8 -> 5
})
}
render(){
const count = this.state.count
console.log('render', count) // 1 -> 0 // 4 -> 3 // 5 -> 4 // 7 -> 5 // 9 -> 6 // 11 -> 7
return (
<div>
<p>{count}</p>
</div>
)
}
}
//render 0
//0
//0
//render 3
//render 4
//Promise 4
//render 5
//Promise 5
//render 6
//timeout 6
//render 7
//timeout 7