React 面试中如何设计 state 结构:状态放哪、如何分组、如何重置?
React 面试中如何设计 state 结构状态放哪、如何分组、如何重置【免费下载链接】front-end-interview-handbookFront End interview preparation materials for busy engineers (updated for 2026)项目地址: https://gitcode.com/GitHub_Trending/fr/front-end-interview-handbook在 React 的 UI 编码面试题中state 设计往往决定了解答的整体质量。front-end-interview-handbook 项目的 React 面试手册 react-state-design 章节中文版给出了明确判断Good state design is often what separates strong interview solutions from weak ones。本文按该文档的内容把 state 设计整理成一条可以照着执行的流程先枚举 UI 真正需要的最小状态集合再决定状态放在哪一层、如何分组、以及如何重置最后说明面试场景下 context 和useReducer通常可以不要的理由。动笔之前先列出 UI 需要的最小状态集合文档把这一步放在最前面原因是面试官经常追问 state 结构本身而干净的 state 形状一旦确定后面的实现会自然展开Before you start coding, spend a minute identifying the minimal set of values the UI actually needs.也就是说在写下第一个useState之前先只列出 UI 渲染和交互真正依赖的值。列出之后下面三节的原则都作用在这份清单上哪些该留在局部、哪些该合并、哪些根本不该存。状态放哪能局部就局部面试题默认放顶层只被一个组件使用的状态不要上提文档给出的反例是把只有Child使用的count提升到App再通过 props 把count和setCount传下去。正确做法是让状态留在使用它的组件内部function App() { return Child /; } function Child() { const [count, setCount] useState(0); return button onClick{() setCount(count 1)}Count: {count}/button; }区别在于重渲染范围count变化时只有Child需要重渲染而不是父组件带动整棵子树。面试场景的默认选择状态放顶层子组件保持无状态文档在 What you need to know for interviews 中给出了面试专用判断由于面试题体量小state 大概率应该放在顶层 / app 层大多数子组件应该是 stateless 的、通过 props 接收数据。只有两种例外适合把状态留在子组件里表单输入框里的临时状态ephemeral state in form inputs不需要跨整个应用共享的状态。状态如何分组三条判断准则把表示同一件事的字段合并进一个 state 对象x和y共同定义一个坐标点就该作为一个单元管理。分开两个useState时每次移动指针都要连续调用setX(e.clientX)和setY(e.clientY)两个 setter更新麻烦且容易漏掉其中一个。合并后一次更新完成function App() { const [point, setPoint] useState({ x: 0, y: 0 }); return ( div onPointerMove{(e) { setPoint({ x: e.clientX, y: e.clientY }); }} p Point: ({point.x}, {point.y}) /p /div ); }用单一 status 字段消灭互相矛盾的状态文档用一个提交表单的例子说明问题如果用isSubmitting、isSubmitted、isError三个布尔值表示表单状态就可能出现setIsSubmitting(true)和setIsSubmitted(true)同时为真的组合——组件正在提交且已提交成功这在语义上不成立。修复方式是把互斥状态合并成一个字符串枚举任何时刻只可能处于其中一个值function ContactForm() { const [status, setStatus] useState(idle); // idle, submitting, success, error function handleSubmit(event) { event.preventDefault(); setStatus(submitting); fetch(/api/submit, { method: POST }) .then(() setStatus(success)) .catch(() setStatus(error)); } return ( form onSubmit{handleSubmit} button typesubmit disabled{status submitting} Submit /button {status success pForm submitted successfully!/p} {status error pSubmission failed. Please try again./p} /form ); }文档给出的好处表单任一时刻只能处于一个状态、错误路径不会把表单错误标记成已提交、也不再需要手动同步多个布尔值。能算出来的值就在渲染时算不要存如果同时存了todos列表和一个count还要用useEffect在todos变化时把count同步成todos.length那就制造了两个必须保持一致的真相来源。正确写法是渲染期间直接派生const [todos, setTodos] useState([Task 1, Task 2]); const count todos.length; // No need to store it separately文档的说明是每次渲染重新计算一个普通变量的开销很小却能消除一整类状态过期的 bug。判断标准一句话凡是能从现有 state 或 props 计算出来的值就在渲染时派生。状态如何重置最直接的重置方式是把每个 state 设回初始值但状态字段一多就要逐个调用 setter容易漏字段。文档给出两条路字段级重置把状态分组并为每种可能的操作定义函数重置时调用这些函数而不是散落的 setter整体重置文档推荐的最干净方式改变组件的key。key变化时 React 会卸载并重建该元素子树里所有useState、ref 和 effect 拥有的资源全部清空function Form() { return ( form input typetext placeholderJohn Doe / buttonSubmit/button /form ); } function App() { const [key, setKey] useState(0); return ( div Form key{key} / button onClick{() setKey((prev) prev 1)}Reset form/button /div ); }工作机制是key变化强制 React 对Form执行 unmount remount。文档同时指出form本身有formElement.reset()这类内置重置方式但key方案对任意组件都有效尤其适合内部状态多、逐字段重置很麻烦的场景。可选的进一步封装把重置封装进自定义 hook调用方只能通过暴露的操作如increment、decrement、reset修改状态拿不到裸的 setter。react-hooks 章节 中的useCounter示例就是这个模式function useCounter(initialValue 0) { const [count, setCount] useState(initialValue); const increment () setCount(count 1); const decrement () setCount(count - 1); const reset () setCount(initialValue); return { count, increment, decrement, reset }; }面试中还用不用 Context 和 useReducer这两问决定了状态放哪的边界文档给出的面试判断是大概率不需要 context面试题的 prop 传递深度在最坏情况下也不超过两三层直接 prop passing 更简单。大概率不需要 reducer面试题的状态变更种类有限把状态更新收敛到几个 action 函数里即可例外是游戏类题目游戏逻辑可以复杂到值得上useReducer。如果确实使用了 context注意文档列出的陷阱中最影响面试代码的两条provider value 每次变化都会让所有消费该 context 的组件重渲染所以频繁更新的数据输入框内容、鼠标位置不要放进 provider应留在局部useState不要把太多不相关的数据塞进同一个 provider按更新频率或关注点拆分成多个 provider。自检与练习入口写代码前可以按文档的原则过一遍清单全部满足再动笔是否已列出 UI 需要的最小状态集合可派生的值如todos.length已改为渲染时计算相关字段如x/y是否合并进了同一个 state 对象互斥状态如提交中/成功/失败是否合并成单个 status 字段不存在矛盾组合除表单临时状态和局部状态外状态是否都在顶层、子组件是否 stateless需要整体重置时是否优先考虑改key而不是逐个字段还原。react-state-design 文档末尾的 Practice questions 一栏给出了配套的练习入口包括 Todo List、Transfer List、Users Database、Wordle、Undoable Counter 等 coding 题以及 controlled/uncontrolled 组件、context 陷阱、如何重置组件 state等 quiz 题可以用来验证上述原则是否真正可用。完整的状态设计原则、context 适用场景主题、鉴权、路由、通知、全局弹窗等和 reducer 适用场景多步表单、状态驱动 UI、有限状态机见 react-state-design 原文useState的陷阱与函数式更新写法见 react-hooks。【免费下载链接】front-end-interview-handbookFront End interview preparation materials for busy engineers (updated for 2026)项目地址: https://gitcode.com/GitHub_Trending/fr/front-end-interview-handbook创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考