前端进阶之旅前端进阶之旅
  • 基础篇HTML/CSS/JS 打底
  • 进阶篇原理与工程化
  • 高频篇面试最常问的那批
  • 精选篇按模块收敛的总结
  • 手写篇常考代码手写实现
  • 面经篇真实面试问题复盘
  • AI 篇NEWAI 时代的前端考点
  • 历年面经NEW按年份追踪真实考点
  • 每日一题每天一道,攒手感
  • 专项自测100 题快速查漏
  • 小程序题库小程序专项刷题
  • 算法题库NEW在线编码即时判题
  • 知识卡片NEW碎片时间过考点
  • 面试题大全常见问题解析
  • AI 答疑NEW随时提问,即时解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • AI 定制路线NEW按你的简历现排
  • AI 知识地图NEW串起全站知识点
  • 原理篇React / Vue 源码拆解
  • HTTP从报文一路讲到 HTTPS
  • 浏览器渲染、事件循环、进程
  • 计算机基础Linux、网络、操作系统
  • 设计模式23 种模式怎么用
  • Node学习指南从环境搭建到服务端
  • NPM工作流script、依赖与发布
  • Docker容器化部署上手
  • Canvas图形与动画实战
  • 前端系统进阶学习大型项目工程化
  • 前端综合文章长期沉淀的实践文
  • 思维导图知识点全景图
  • 学习路线按图索骥不跑偏
  • AI 热点NEWAI 每日动态
  • 公众号动态公众号历史文章
  • 博客动态站长的技术博客
  • 开发者导航常用工具与文档站
  • 基础篇HTML/CSS/JS 打底
  • 进阶篇原理与工程化
  • 高频篇面试最常问的那批
  • 精选篇按模块收敛的总结
  • 手写篇常考代码手写实现
  • 面经篇真实面试问题复盘
  • AI 篇NEWAI 时代的前端考点
  • 历年面经NEW按年份追踪真实考点
  • 每日一题每天一道,攒手感
  • 专项自测100 题快速查漏
  • 小程序题库小程序专项刷题
  • 算法题库NEW在线编码即时判题
  • 知识卡片NEW碎片时间过考点
  • 面试题大全常见问题解析
  • AI 答疑NEW随时提问,即时解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • AI 定制路线NEW按你的简历现排
  • AI 知识地图NEW串起全站知识点
  • 原理篇React / Vue 源码拆解
  • HTTP从报文一路讲到 HTTPS
  • 浏览器渲染、事件循环、进程
  • 计算机基础Linux、网络、操作系统
  • 设计模式23 种模式怎么用
  • Node学习指南从环境搭建到服务端
  • NPM工作流script、依赖与发布
  • Docker容器化部署上手
  • Canvas图形与动画实战
  • 前端系统进阶学习大型项目工程化
  • 前端综合文章长期沉淀的实践文
  • 思维导图知识点全景图
  • 学习路线按图索骥不跑偏
  • AI 热点NEWAI 每日动态
  • 公众号动态公众号历史文章
  • 博客动态站长的技术博客
  • 开发者导航常用工具与文档站
首页程序员面试题库React 派生状态为什么不需要 useEffect
ReReact副作用与同步

React 中由 props/state 计算出的值为什么通常不该放进 Effect 再 setState?

能够由当前输入算出的展示结果,先在渲染期间计算;只有同步外部系统时才需要考虑 Effect。

前端进阶之旅 · 一题精讲更新于 2026.09.06
React#副作用与同步#Effect#React 性能#安全
先看核心答案
理解线索

输入、派生结果和外部同步分开建模

  1. 独立输入选中项、优惠规则等决定业务结果的最小状态
  2. 派生结果本次渲染直接读取当前输入计算合计与提示
  3. 外部同步通知第三方组件或订阅系统时另行处理生命周期

先判断某个值能否被用户独立改变,再决定它是不是需要单独保存的状态。

核心回答

先记住这个答案

派生值如果完全由当前 props 或 state 决定,通常直接在渲染中计算,不再用一份 state 保存它。用 Effect 更新派生 state,会让一次输入变化先得到包含旧派生值的渲染,再安排一次更新;同时增加两份数据必须保持一致的负担。计算确实昂贵时可评估 useMemo,用户能独立编辑、撤销或保留的草稿则是另一类状态,不能简单删掉。

  • 保存最少的独立状态,展示值从它推导
  • Effect 同步外部系统,不负责重复计算展示值
  • useMemo 用于成本优化,不改变数据的来源

为什么多存一份结果会制造时序问题

假设订单里保存了商品数量,又通过 Effect 把总价写到另一个 state。数量从一改成二时,组件先拿到新数量与旧总价,Effect 执行后才产生新总价。若其他逻辑读取这次提交,就必须解释两者暂时不一致的情况,而直接用数量和单价计算不会建立这种同步缺口。

这不是要求把所有工作塞进 render。计算必须纯粹,不能顺便写数据库、修改传入数组或启动请求。纯计算可能随着渲染重试再次执行,结果应只依赖显式输入;外部操作则需要事件处理器、数据层或恰当的 Effect 生命周期。

订单合计与可编辑报价不是同一种状态

订单小计、筛选后的商品和是否达到免邮门槛,可以从商品列表、数量和地区规则推导。把这些结果同时保存,容易出现只更新其中一项的维护错误。测试时应覆盖商品删除、数量变化和地区切换,并检查同一组输入始终得到一致的展示结果。

但销售人员手动修改的报价不是商品价格的简单映射:它可能需要保留折扣理由、审批状态以及撤销记录。这时应把自动建议价和已编辑报价区分开,明确什么时候重新计算建议、什么时候保留人工输入,不能借“避免派生状态”覆盖用户尚未保存的编辑。

什么时候需要缓存,以及怎样判断收益

如果合计只是几次乘加,直接计算通常比增加缓存管理更清楚。面对较大的搜索索引或复杂聚合,可以先测量真实交互中的成本,再用 useMemo 缓存纯计算。依赖必须完整,输入的引用变化也应符合状态不可变更新的约定。

不要把 useMemo 当成永不失效的存储,更不能为了稳定某个副作用执行次数而把业务正确性绑在缓存上。即使去掉缓存,页面也应给出正确结果。若数据量已经让主线程明显阻塞,还应考虑减少输入规模、调整算法或移动计算,而不是只增加一个 Hook。

回答前,多想一步

容易答错的地方

把避免 Effect 理解成禁止 Effect
连接 WebSocket、清理订阅、同步第三方地图等确实涉及外部系统。问题在于用副作用把内部可计算的数据再复制一遍;判断依据是数据关系与同步目标,而不是看到 useEffect 就机械删除。
认为所有 props 初始化 state 都错误
有些控件需要从初始值建立独立草稿,后续输入有自己的生命周期。这种设计可以成立,但必须约定外部初始值改变时是否重置,以及如何处理未保存修改,不能默认为永远跟随 props。
试着用自己的话回答

面试官还会怎么问?

派生值每次渲染都计算,是否一定很慢?

不一定,要看计算规模和触发频率。简单布尔判断、少量合计通常没有可感知成本;应在真实交互中测量瓶颈,避免为了省几次运算引入更难维护的重复状态。

派生结果需要发送给第三方图表时怎么做?

先在渲染中得到纯粹的结果,再通过负责图表实例的同步逻辑更新外部对象。结果的计算与外部同步是两个职责,不能因为后者需要 Effect,就把前者也写成 setState 链。

多个组件都需要同一个派生值时放在哪里?

可以在共同父组件计算后传递,也可以放在共享状态层的选择器中。关键是让计算基于同一份权威输入,避免每个组件维护一份可以独立过期的结果副本。

从一道题,走向一组知识

把知识连起来

副作用与同步

当 React 需要根据 props 变化重置子组件状态时,为什么优先改 key 而不是写 Effect 清状态?

派生结果不需要重复保存;整份编辑状态需要重置时,应进一步区分组件身份变化。

Hooks 与复用

React 中 useRef 和 useState 都能跨渲染保存数据,二者的本质区别和适用场景是什么?

如果某个值不参与界面展示,继续判断它应放在 ref 还是作为渲染状态保存。

参考资料

  • You Might Not Need an Effect

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. 为什么多存一份结果会制造时序问题
  3. 订单合计与可编辑报价不是同一种状态
  4. 什么时候需要缓存,以及怎样判断收益
  5. 容易答错的地方
  6. 面试官还会怎么问
  7. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑