【React】setState (useState) 是怎么记住上一个状态值的?

在 React 中,setState 通过 React 内部的状态管理机制来记住上一个状态值。即使每次组件重新渲染时,函数组件会被重新执行,React 仍能通过其内部的状态管理系统保持和追踪组件的状态变化。下面详细解释其工作原理:

1. setState 的工作原理

setState 是 React 的核心状态更新方法,用于更新组件的状态,并且触发重新渲染。React 中,组件的状态存储在组件实例中(类组件)或通过 React 的 Hook 系统(函数组件)进行管理。在调用 setState 时,React 并不会立即更新状态,而是将更新请求放入一个队列中,并批量处理这些更新,以提高性能。

在函数组件中,useState 是一个用于管理状态的 Hook。每次调用 setState 时,React 将使用更新队列,并在合适的时机将最新的状态重新传递给组件,确保每次渲染时都能够记住最新的状态。

2. 函数组件的状态记忆(useState

函数组件本质上是无状态的,函数内部的局部变量在每次渲染后都会被销毁。然而,React 通过 useState Hook 来保持状态的持久化,它会将状态与组件进行关联,即使组件重新渲染,React 仍然能够保持状态。

js 复制代码
function MyComponent() {
  const [count, setCount] = useState(0); // 初始化状态为 0

  return (
    <button onClick={() => setCount(count + 1)}>
      {count}
    </button>
  );
}

在这个例子中,useState(0) 初始化了 count 为 0,setCount 是用于更新 count 值的函数。每次点击按钮时,setCount 会更新 count 的值,并触发组件重新渲染。

工作机制:
  1. 首次渲染 :当组件第一次渲染时,React 会初始化状态并将初始值(如 0)存储在内部的状态列表中。
  2. 后续渲染 :每次组件重新渲染时,React 不会重新初始化状态,而是从其内部存储中取出最新的状态值,并将其传递给组件函数中的 useState
  3. 状态更新 :当 setState(如 setCount)被调用时,React 将更新的状态值存入其内部的状态存储,并在下一次渲染时使用该值。通过这种方式,React 能够记住并管理状态值。
js 复制代码
function App() {
    const [index, setIndex] = useState(0)
	// 
    const handleClick = () => {
        setIndex(index + 1)
        setIndex(index + 1)
        setIndex(index + 1)
        console.log('index改变', index);
    }

    return (
        <div className="App">
            {/*经过一次点击后 index 为 1,而不是3 ,是因为 setState 队列中如果有相同的 setState 会自动忽略后续的 set 相当于自带防抖*/}
            {/*需要需要保留上一次 set 的值,需要传入一个回调 参数用来接收上一次的值,队列完成更新后再调用 render 渲染组件*/}
            <div>{index}</div>
            <button onClick={handleClick}>index + 1</button>
        </div>
    );
}

如果 setState 不相同呢?

js 复制代码
const handleClick = () => {
    setIndex(index + 1)
    setIndex(index + 2)
    setIndex(index + 3)
    console.log('index改变', index);
}

此时页面展示为 3,因为 set state 不同,后续会正常执行异步操作。

3. React 如何记住状态(闭包和 Hook 内部机制)

React 通过闭包和 Hooks 系统来管理状态,确保在多次渲染之间保持状态的一致性。useState 背后的工作方式是,React 为每个组件实例维护了一个"状态钩子"链表,组件每次渲染时,它依次从这个链表中获取对应的状态值。

流程概述:
  1. 状态存储:每个组件的状态被存储在 React 内部的某个数据结构中,通常是一个状态列表。
  2. 状态链表 :每个调用 useState 的组件,都有一个状态链表,其中存储了状态值和 setState 函数。
  3. 状态更新 :当调用 setState 时,React 会更新链表中的状态值,然后调度一次渲染。
  4. 下一次渲染时:在下一次渲染时,React 从该链表中获取最新的状态值,确保状态是连续且正确的。
使用 setState 更新状态:
js 复制代码
const [count, setCount] = useState(0);

function handleClick() {
  setCount(prevCount => prevCount + 1);
}

这里 setCount 可以接收一个函数,该函数的参数 prevCount 是 React 自动传入的上一次的状态值。即使多个 setState 在同一渲染周期中执行,React 也会确保传递的状态值是最新的。

4. React 的批量更新机制

React 在同一个事件或生命周期方法中会对多个状态更新进行批量处理。即使多次调用 setState,React 也不会立即更新状态,而是等到事件处理完后再进行批量更新,并触发一次渲染。

js 复制代码
const [count, setCount] = useState(0);

function handleClick() {
  setCount(count + 1);
  setCount(count + 1);
}

在这种情况下,虽然两次调用 setCount,React 会批量更新,并只会触发一次渲染,最终 count 只会增加一次。

总结

  • 状态持久化 :React 通过 useState 和内部状态存储系统来管理状态,每次渲染时,React 会从状态链表中获取最新状态,并保持状态的连续性。
  • 闭包与 Hooks :React 的 Hooks 系统和闭包机制确保状态不会在多次渲染中丢失,setState 会更新状态链表,并在下一次渲染时应用最新状态。
  • 批量处理 :React 对 setState 调用进行了优化,多个 setState 会被批量处理,从而避免不必要的多次渲染。
相关推荐
AlienZHOU3 小时前
AI Coding 时代下,我的技术面试实践分享
前端·后端·面试
Captaincc6 小时前
AI用量v0.1.11更新发布 新增 jusage doctor 诊断指令 托盘展示token 和余额 新增 AutoClaw 支持
前端·后端·vibecoding
计算机魔术师7 小时前
德国Wiki被黑后两周,OpenAI终于把模型失控的账本摊开了
前端
kyriewen8 小时前
我让 AI 当面试官面了我一轮:第 3 个追问我就卡住了(附 10 道追问清单)
前端·面试·ai编程
IT_陈寒8 小时前
Python的GIL把我坑惨了,多线程跑得比单线程还慢
前端·人工智能·后端
前端snow8 小时前
ai agent --- 多agent框架之图编排引擎-langgraph
前端
竹林8188 小时前
OmniPic Studio v3.2.1 核心技术架构与全平台发版解析文档
前端·浏览器
JamesZhang800788 小时前
页面内存只涨不跌? 一次泄漏排查, 牵出 WeakMap 的诞生
前端
Z小明8 小时前
第 6 章 组件进阶
前端·vue.js
江华森8 小时前
HTTP请求的完整过程详解:从DNS解析到TCP挥手的微秒级实战分析
前端