原生JS/Node复刻React useState:状态变量无法同步更新求解
复刻React useState:解决状态更新后变量不同步问题
我尝试在原生JavaScript/Node中复刻React的useState函数,当前实现代码如下:
let callIndex = -1 const stateValues = [] const useState = (initialValue) => { callIndex++ // 0 const currentCallIndex = Number(callIndex) // 0 if (stateValues[currentCallIndex] === undefined){ stateValues[currentCallIndex] = initialValue } const setValue = (newValue) => { stateValues[currentCallIndex] = newValue } return [stateValues[currentCallIndex], setValue] } const [countA, setCountA] = useState(1) const [countB, setCountB] = useState(-1)
这个实现的问题是:解构得到的countA、countB只是初始值的副本,并没有和stateValues数组的对应位置形成动态关联。调用setValue更新状态后,stateValues里的值确实更新了,但countA、countB始终是初始值:
setCountA(3) // LOGs-> stateValues[0]: 3, stateValues[1]: -1, countA: 1, countB: -1 setCountA(5) setCountB(9) // LOGs-> stateValues[0]: 5, stateValues[1]: 9, countA: 1, countB: -1 setCountA(2) setCountB(5) // LOGs-> stateValues[0]: 2, stateValues[1]: 5, countA: 1, countB: -1
我可以让useState返回箭头函数来获取最新状态,但每次取值都要调用函数。有没有更贴近React风格的方式,不用调用函数,直接通过countA这类变量获取更新后的值?
解决方案:模拟React的组件渲染周期
React的核心逻辑是状态更新后重新执行组件函数,重新执行useState时会从状态存储中读取最新值,解构得到的变量自然就是最新状态。我们可以复刻这个机制:
let callIndex = -1 const stateValues = [] // 模拟React的渲染调度:每次渲染重置callIndex,重新执行组件函数 function render(component) { callIndex = -1 component() } const useState = (initialValue) => { callIndex++ const currentCallIndex = callIndex if (stateValues[currentCallIndex] === undefined) { stateValues[currentCallIndex] = initialValue } const setValue = (newValue) => { stateValues[currentCallIndex] = newValue // 状态更新后触发重新渲染 render(component) } return [stateValues[currentCallIndex], setValue] } // 把所有状态相关逻辑放在"组件"函数中 function component() { const [countA, setCountA] = useState(1) const [countB, setCountB] = useState(-1) // 这里的countA、countB每次渲染都是最新值 console.log(`countA: ${countA}, countB: ${countB}, stateValues: ${JSON.stringify(stateValues)}`) // 暴露setter方便测试(实际场景中可在组件内部处理更新逻辑) window.setCountA = setCountA window.setCountB = setCountB } // 首次渲染组件 render(component)
测试效果
调用setter时会自动触发重新渲染,此时解构得到的变量就是最新状态:
setCountA(3) // 输出:countA: 3, countB: -1, stateValues: [3,-1] setCountB(9) // 输出:countA: 3, countB: 9, stateValues: [3,9] setCountA(2) // 输出:countA: 2, countB: 9, stateValues: [2,9]
原理说明
- 每次调用
setValue更新状态后,会触发render函数重置callIndex并重新执行组件函数 - 组件函数重新执行时,会再次调用
useState,此时callIndex从0开始计数,对应stateValues中的最新值,解构得到的countA、countB自然就是最新状态 - 这完全贴合React的运行逻辑:状态更新驱动组件重新渲染,保证状态变量始终是最新值
内容的提问来源于stack exchange,提问作者varChar16
相关产品推荐
相关产品推荐

