memo、useMemo、useCallback 分别缓存什么?

先理解原理和示例,再练习完整口述与追问。

memo 可按 props 比较跳过部分父级引发的重渲染;useMemo 缓存计算结果,useCallback 缓存函数引用。自身 state 或使用的 Context 改变仍可能触发更新。先测量,避免增加无效缓存与依赖维护成本。

memo 缓存组件在可跳过条件下的渲染,useMemo 缓存一次计算结果,useCallback 缓存函数引用。它们解决不同层面的重复工作;依赖数组中的值仍按 Object.is 等规则比较。memo 组件自己的 state 或所读 Context 变化仍会使它更新,父传入每次新建的对象也可能让浅比较无法命中。

大表格行只接收稳定 row 与 onSelect,可以先用 Profiler 看是否因无关父更新频繁执行;真正昂贵的排序可用 useMemo 缓存。若 onSelect 每次重新创建导致 memo 行更新,再根据需要用 useCallback;只给一个便宜按钮包多层缓存,比较与维护成本可能更高。

缓存是性能优化,不能依赖它维持正确性或保存必须可靠存在的业务状态。自定义比较函数若漏了函数 prop,可能让子组件继续使用旧闭包。

memo 作用于组件,可在 props 相等时跳过部分父级引起的重新渲染;useMemo 缓存一次计算的结果,useCallback 缓存函数引用。它们是性能优化,不改变业务应有的语义,也不能阻止自身 state 或 Context 变化带来的更新。我会用 Profiler 确认瓶颈,再决定是否值得缓存。

面试官可能继续问追问与完整解答展开收起

传入新对象为何让 memo 无效?启用了 React Compiler 后哪些手工优化可减少,为什么不能假定项目已经启用?React 官方 memo

新建对象或函数即使内容看起来一样,引用也不同,默认比较可能认为 props 变了。启用且受支持的 React Compiler 可自动完成部分记忆化,减少手工 memo,但必须确实配置并验证;自定义比较还必须考虑函数闭包,否则可能保留旧行为。