跳到主要内容

useState

面试速答(30 秒版 TL;DR)

  • useState 是 React 函数组件最基础的本地状态 Hook。
  • 它返回 [state, setState],当状态更新后,React 会调度组件重新渲染。
  • React 18 下要重点记 3 个点:
    • 状态更新是异步调度的,不要立刻假设读取到的是新值
    • 多次更新可能会被 batching(批处理)
    • 新值如果经 Object.is 比较后认为没变,React 可以跳过无意义重渲染
  • 面试不要只会背语法,更要说明:状态为什么会触发 render,以及闭包、批处理、函数式更新这些边界。

1. 基本用法

const [count, setCount] = useState(0)

含义很直接:

  • count:当前状态值
  • setCount:发起更新

2. 为什么调用 setState 会重新渲染

因为 React 把 state 看成组件输出 UI 的输入之一。

当 state 变化时,React 需要重新执行组件函数,重新计算:

  • JSX 长什么样
  • 子组件传什么 props
  • 哪些节点需要更新

所以“更新 state”本质上是在告诉 React:

这棵 UI 相关输入变了,请重新计算一遍。

3. React 18 下最重要的 3 个知识点

3.1 批处理更普遍了

React 18 里,很多异步场景下的多次更新也会自动批处理。

setA(1)
setB(2)

通常不会触发两次单独提交,而是合并处理,减少额外渲染。

3.2 闭包旧值

setCount(count + 1)
setCount(count + 1)

如果这里的 count 来自同一次 render,最终可能只加一次。

更稳的写法是函数式更新:

setCount(c => c + 1)
setCount(c => c + 1)

3.3 相同值优化

如果新旧值经比较后没变化,React 可能跳过无意义更新。

4. 惰性初始化

如果初始值计算比较重,可以传函数:

const [state] = useState(() => createInitialState())

这样只在首次初始化时执行一次。

5. useStateuseReducer 怎么选

5.1 useState

更适合:

  • 单值
  • 简单对象
  • 更新逻辑直接

5.2 useReducer

更适合:

  • 多分支 action
  • 状态转移复杂
  • 需要统一收口更新逻辑

6. 面试高频答法

Q1:为什么 setState 后不能马上拿到新值?

因为它不是立即同步改变量,而是发起一次状态更新调度,真正的新值会在下一轮渲染里体现。

Q2:为什么推荐函数式更新?

因为它基于“上一个最新状态”计算,能避免闭包旧值问题,尤其适合:

  • 连续多次更新
  • 异步回调更新

Q3:React 18 的自动批处理有什么意义?

减少不必要的重复渲染,让多个相关状态更新能合并提交,提升性能和一致性。

常见追问

1)对象 state 更新为什么要返回新对象?

因为 React 依赖引用变化判断状态是否变化,直接改原对象容易让更新失效或难以追踪。

2)一个组件里可以有很多个 useState 吗?

可以。拆分多个 state 往往比一个大对象更清晰,前提是它们语义上确实独立。

易错点/坑

  • 以为 setState 是立即同步赋值。
  • 连续 setCount(count + 1) 却没意识到闭包问题。
  • 直接修改对象/数组原值而不是返回新引用。

速记要点(可背诵)

  • useState:最基础的本地状态 Hook。
  • React 18 高频点:自动批处理、闭包旧值、函数式更新。
  • 页面要变,就改 state;改 state,本质是在触发新一轮 UI 计算。