本文在我的 Github博客 https://github.com/Jacky-Summer/personal-blog 同步更新
前言
本篇写的 setState(涉及源码部分)是针对 React15 版本,即是没有 Fiber 介入的;为了方便看和写,所以选择旧版本,Fiber 写起来有点难,先留着将会写。setState 在 React 15 的原理能理解,16 版本的也是大同小异。
虽然已经用 React Hooks 很久了,React15 的this.setState()
形式都很少用了,但依然是站在回顾与总结的角度,看待 React 的变迁和发展,所以最近开始重新回顾以前一知半解的一些原理问题,慢慢沉淀技术。
setState 经典问题
setState(updater, [callback])
React 通过 this.setState()
来更新 state,当使用 this.setState()
的时候 ,React 会调用 render 方法来重新渲染 UI。
setState 的几种用法就不用我说了,来看看网上讨论 setState 比较多的问题:
批量更新
import React, { Component } from 'react'
class App extends Component {
state = {
count: 1,
}
handleClick = () => {
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
}
render() {
return (
<><button onClick={this.handleClick}>加1button><div>{this.state.count}div>>
)
}
}
export default App
点击按钮触发事件,打印的都是 1,页面显示 count 的值为 2。
这就是常常说的 setState 批量更新,对同一个值进行多次 setState , setState 的批量更新策略会对其进行覆盖,取最后一次的执行结果。所以每次 setState 之后立即打印值都是初始值 1,而最后页面显示的值则为最后一次的执行结果,也就是 2。
setTimeout
import React, { Component } from 'react'
class App extends Component {
state = {
count: 1,
}
handleClick = () => {
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
setTimeout(() => {
this.setState({
count: this.state.count + 1,
})
console.log(this.state.count) // 3
})
}
render() {
return (
<><button onClick={this.handleClick}>加1button><div>{this.state.count}div>>
)
}
}
export default App
点击按钮触发事件,发现 setTimeout 里面的 count 值打印值为 3,页面显示 count 的值为 3。setTimeout 里面 setState 之后能马上能到最新值。
在 setTimeout 里面,setState 是同步的;经过前面两次的 setState 批量更新,count 值已经更新为 2。在 setTimeout 里面的首先拿到新的 count 值 2,再一次 setState,然后能实时拿到 count 的值为 3。