setState是什么?
setState是用于更新组件状态的方法,React保证在setState执行之后会调用render函数进行页面渲染更新
- 第一个参数可以是一个对象或者是一个函数
- 第二个参数是一个回调函数,获取更新之后的数据
import React, { component } from 'react'
export default class App extends Component {
constructor(props) {
super(props)
this.state = {
message: 'hello',
}
}
changeMessage() {
this.setState({
message: 'hello world'
})
}
render() {
return (
<div>
<h2>{this.state.message}</h2>
<button onClick={e => this.changeMessage()}>update message</button>
</div>
)
}
}
更新类型
- 异步更新
setState 的“异步”并不是说内部由异步代码实现,其实本身执行的过程和代码都是同步的,只是合成事件和钩子函数的调用顺序在更新之前,导致在合成事件和钩子函数中没法立马拿到更新后的值,形成了所谓的“异步”,当然可以通过第二个参数setState(partialState, callback)中的callback拿到更新后的结果
- 在组件生命周期钩子(除
componentDidUpdate) 或 React合成事件中,为异步更新
import React, { component } from 'react'
export default class App extends Component {
constructor(props) {
super(props)
this.state = {
message: 'hello',
}
}
changeMessage() {
this.setState({
message: 'hello world'
}, () => {
console.log(this.state.message) // hello world
})
console.log(this.state.message) // hello
}
render() {
return (
<div>
<h2>{this.state.message}</h2>
<button onClick={e => this.changeMessage()}>update message</button>
</div>
)
}
}
- 同步更新
- 使用setTimeout包裹时,变为同步更新
import React, { component } from 'react'
export default class App extends Component {
constructor(props) {
super(props)
this.state = {
message: 'hello',
}
}
changeMessage() {
// 使用setTimeout包裹时,变为同步更新
setTimeout(() => {
this.setState({
message: 'hello world'
})
console.log(this.state.message) // hello world
}, 0)
}
render() {
return (
<div>
<h2>{this.state.message}</h2>
</div>
)
}
}
- 使用原生事件进行事件绑定时,变为同步更新
import React, { component } from 'react'
export default class App extends Component {
constructor(props) {
super(props)
this.state = {
message: 'hello',
}
}
componentDidMount() {
const btn = document.getElementById('btn')
// 使用原生事件进行事件绑定时,变为同步更新
btn.addEventListen('click', () => {
this.setState({
message: 'hello world'
})
console.log(this.state.message) // hello world
})
}
render() {
return (
<div>
<h2>{this.state.message}</h2>
<button id='btn'>update message</button>
</div>
)
}
}
小结
在组件生命周期 或 React合成事件中,为异步更新
在setTimeout中调用 或 使用原生事件进行事件绑定时调用,变为同步更新页面上显示为2 } render() { return ( <div> <h2>{this.state.message}</h2> <button onClick={e => this.changeMessage()}>update message</button> </div> ) } }
3. 批量更新
import React, { component } from 'react'
export default class App extends Component {
constructor(props) {
super(props)
this.state = {
count: 1,
}
}
addCount() {
this.setState({
count: this.state.count + 1,
})
console.log(this.state.count) // 1
this.setState({
count: this.state.count + 1,
})
console.log(this.state.count) // 1
this.setState({
count: this.state.count + 1,
})
console.log(this.state.count) // 1
this.setState({
count: this.state.count + 1,
})
console.log(this.state.count) // 1
// 批量更新,覆盖操作,取最后一次执行的结果,此时页面上显示为2
// 等价于如下操作,只取最后一次
Object.assign(previousState, {
{count: this.state.count + 1},
{count: this.state.count + 1},
{count: this.state.count + 1},
{count: this.state.count + 1},
})
}
render() {
return (
<div>
<h2>{this.state.count}</h2>
<button onClick={e => this.addCount()}>update message</button>
</div>
)
}
}
- 若第一个参数使用函数,虽然还是批量更新,但是由于可以拿到preState,因此可以顺利完成累加;不过第二个参数的回调函数会在批量更新结束后统一按顺序调用,因此输出结果都为最终结果
addCount() {
this.setState((preState, props) => {
return {count: preState.count + 1}
}, () => {
console.log('callback: ', this.state.count) // callback: 5
})
console.log('@: ', this.state.count) // @: 1
this.setState((preState, props) => {
return {count: preState.count + 1}
}, () => {
console.log('callback: ', this.state.count) // callback: 5
})
console.log('@: ', this.state.count) // @: 1
this.setState((preState, props) => {
return {count: preState.count + 1}
}, () => {
console.log('callback: ', this.state.count) // callback: 5
})
console.log('@: ', this.state.count) // @: 1
this.setState((preState, props) => {
return {count: preState.count + 1}
}, () => {
console.log('callback: ', this.state.count) // callback: 5
})
console.log('@: ', this.state.count) // @: 1
}