)
【免费下载链接】open-slideA slide framework built for agents.项目地址https://gitcode.com/gh_mirrors/op/open-slide点击查看免费下载本文基于 open-slide 仓库内 Vercel React Best Practices 技能中的rerender-dependencies规则展开。该规则用于 React/Next.js 代码编写、审查与重构指导开发者将useEffect依赖从对象收窄为原始值避免多余的副作用执行并将派生状态计算移出 effect。读完本文你将掌握一套可在任何 React 项目中直接落地的 effect 依赖收窄方法论并通过 open-slide 源码中的真实案例如useMediaQuery、useIsMobile、useSlideModule看到它的落地形态。规则定位在 React 性能优化全景中的坐标open-slide 仓库内嵌的 vercel-react-best-practices 是一份由 Vercel Engineering 维护的 React / Next.js 性能优化指南共 70 条规则、8 大分类按影响级别从 CRITICAL消除瀑布式请求、Bundle 体积优化到 LOW高级模式排序。本次聚焦的rerender-dependenciesNarrow Effect Dependencies属于第 5 类Re-render Optimization重渲染优化影响级别 MEDIUM其核心目标是最小化 effect 的重复执行次数impactDescription: minimizes effect re-runs。在该技能的分类表中同类规则还包括rerender-derived-state订阅派生布尔值而非连续原始值rerender-derived-state-no-effect渲染期间派生状态而非用 effect 同步rerender-defer-reads把状态读取推迟到回调使用点rerender-move-effect-to-event把交互逻辑放进事件处理器而非 effectrerender-split-combined-hooks拆分依赖不同的组合 Hookrerender-dependencies与这些规则互为补充它们共同回答什么时候不要用 effect、用了 effect 该依赖什么这一核心问题。提示本技能文档主要为 Agent / LLM 在维护、生成或重构 React/Next.js 代码时遵循而设计见 AGENTS.md但对人工开发者同样适用。本文也适合作为给 Agent 的代码审查 / 重构提示词使用。核心规则依赖数组写原始值不写对象规则原文非常简洁在useEffect依赖数组中指定原始值primitive而非对象以最小化 effect 的重跑次数。其背后的原理是 React 的依赖比较机制effect 的依赖数组使用Object.is对前后两次渲染的依赖值做浅比较。两个不同的对象引用即使内容完全相同也不相等因此只要父级重新渲染导致对象重建effect 就会重新执行——哪怕 effect 内部只用到对象里的一个字段。反例依赖整个对象// Incorrectuser 对象的任何字段变化都会触发重跑 useEffect(() { console.log(user.id) }, [user])只要user对象的引用发生变化例如状态更新产生了新对象即使user.id没有变化这个 effect 也会重新执行。正例依赖原始字段// Correct仅当 id 变化时才重跑 useEffect(() { console.log(user.id) }, [user.id])user.id是原始值string/number只有它真正变化时依赖比较才会判定为不相等effect 才会重跑。适用范围说明这条规则针对的是effect 内部只读取对象的一个或少数几个字段的场景。若 effect 确实需要响应对象的多数字段变化依赖整个对象反而是正确的写法若需要的是引用稳定而非值变化则应考虑useCallback/useMemo/ref 等方案可参见同技能中的advanced-use-latest、advanced-event-handler-refs等规则。派生状态把计算移出 effect规则的第二个要点是对于派生状态直接在渲染期间计算不要在 effect 内计算并依赖连续变化的原始值。反例监听连续值导致 effect 高频触发// Incorrect: 宽度 767、766、765… 每次变化都会触发 useEffect(() { if (width 768) { enableMobileMode() } }, [width])width是连续变化的数值浏览器缩放窗口时它会以像素为单位不断更新。即便 effect 真正关心的只是是否小于 768这个布尔结论width的每一次变化都会让 effect 重新执行。正例渲染期派生布尔值effect 只依赖布尔值// Correct: 只在布尔值发生翻转时执行 const isMobile width 768 useEffect(() { if (isMobile) { enableMobileMode() } }, [isMobile])isMobile是布尔值它只会在跨过 768 断点时翻转因此 effect 只在移动端模式真正切换时执行一次。这一步同时贯彻了本技能另外两条相邻规则的思想rerender-derived-state订阅派生布尔状态而非连续值减少重渲染频率rerender-derived-state-no-effect在渲染期间派生状态而非用 effect 存储状态避免多余渲染与状态漂移state drift。关于后者规则文件给出了一个更彻底的示范——如果派生值只是用于展示连 effect 都不需要// Incorrect: 冗余的 state effect 同步 function Form() { const [firstName, setFirstName] useState(First) const [lastName, setLastName] useState(Last) const [fullName, setFullName] useState() useEffect(() { setFullName(firstName lastName) }, [firstName, lastName]) return p{fullName}/p } // Correct: 渲染期间直接派生 function Form() { const [firstName, setFirstName] useState(First) const [lastName, setLastName] useState(Last) const fullName firstName lastName return p{fullName}/p }open-slide 源码中的落地验证open-slide 是一个为 Agent 打造的幻灯片框架A slide framework built for agents其核心包 packages/core 内含大量 React 组件播放器、检查器、演示控制台、侧边栏等是检验这些规则的理想现场。在全部约 40 个组件文件、上百处useEffect调用中我们能看到本规则与相邻规则的实践痕迹。验证一useMediaQuery——把连续值收敛为布尔值use-media-query.ts 是订阅派生布尔状态的标准实现export function useMediaQuery(query: string): boolean { const [matches, setMatches] useState(() matchesMediaQuery(query)); useEffect(() { const mql window.matchMedia(query); setMatches(mql.matches); const onChange (e: MediaQueryListEvent) setMatches(e.matches); mql.addEventListener(change, onChange); return () mql.removeEventListener(change, onChange); }, [query]); return matches; }依赖数组只有query这个字符串原始值——查询字符串不变化时监听器不会重建返回值为布尔matches组件订阅的是查询是否命中这一派生布尔值而非任何连续数值这与rerender-derived-state规则订阅派生布尔状态而非连续值完全一致。验证二useIsMobile——布尔断点替代逐像素监听use-is-mobile.ts 直接复用上面的 Hook// Matches Tailwinds md breakpoint — below it the slide viewer hides desktop // navigation chrome and relies on tap-to-navigate instead. const QUERY (max-width: 767.98px); export function useIsMobile(): boolean { return useMediaQuery(QUERY); }这正是规则中isMobile width 768场景的工程化版本它不暴露连续像素宽度而是暴露(max-width: 767.98px)的布尔结果。消费方如 player.tsx、slide.tsx在移动端布局切换时才会触发一次状态更新与重渲染而不会在每次窗口尺寸微调时都被通知。从源码结构看这正是effect 依赖布尔派生值而非连续原始值这一规则在真实产品中的直接应用。验证三useSlideModule——稳定的原始依赖与事件订阅清理use-slide-module.ts 演示了依赖收窄 正确清理的完整写法export function useSlideModule(slideId: string) { const [slide, setSlide] useStateSlideModule | null(null); const [error, setError] useStatestring | null(null); const loadSeqRef useRef(0); const reload useCallback( (reset: boolean) { // ... 通过 seq 序号防止过期 Promise 覆盖新结果 }, [slideId], // 依赖收窄为原始字符串 ); useEffect(() { reload(true); }, [reload]); useEffect(() { if (!import.meta.hot) return; let cancelled false; const handler (data: unknown) { /* ... */ }; import.meta.hot.on(open-slide:slide-changed, handler); return () { cancelled true; import.meta.hot?.off(open-slide:slide-changed, handler); }; }, [slideId, reload]); // 依赖为原始值 引用稳定的 callback }这里可以看到两条与本规则互补的最佳实践回调引用稳定reload被useCallback包裹依赖仅为原始值slideId因此第一个 effect 只在 slideId 变化时重跑事件订阅的清理第二个 effect 在订阅import.meta.hot事件后返回清理函数防止模块卸载后 handler 残留——这也是 effect 正确性的基本要求对应规则集中client-event-listeners的去重/清理全局事件监听思想。验证四交互逻辑优先放事件处理器规则补充强调不要把交互动作建模为 state effect。open-slide 的 inline-text-editor.tsx 中双击进入编辑的交互直接绑定在事件监听器内useEffect(() { if (!active) return; const onDblClick (event: MouseEvent) { // ...判断命中的可编辑锚点 startInlineEdit({ ...hit, point: { x: event.clientX, y: event.clientY }, selectWord: true }); }; // 注册 / 清理 }, [/* 相关依赖 */]);这符合rerender-move-effect-to-event的精神事件驱动的副作用点击、双击、拖拽应尽量在事件处理器内执行避免用状态 effect 模拟导致重复副作用。当然事件监听器的注册与注销本身放在 effect 里是正确的——这里收窄的应是 effect 的依赖而不是把注册监听这种订阅逻辑移出 effect。延伸依赖数组中的其他陷阱相邻规则速览rerender-dependencies不是孤立的。同分类中以下规则与本规则高度相关重构时建议一并检查相邻规则文件一句话要点rerender-derived-state.md订阅派生布尔状态如useMediaQuery((max-width: 767px))而非连续值rerender-derived-state-no-effect.md能在渲染期算出的值就别存 state、别用 effect 同步rerender-move-effect-to-event.md点击/提交等交互逻辑放进事件处理器别建模成 stateeffectrerender-defer-reads.md只在回调里读的动态状态searchParams/localStorage别订阅rerender-split-combined-hooks.md依赖不同的多个任务拆成多个 Hook避免无谓联动重跑rerender-simple-expression-in-memo.md结果类型为原始值的简单表达式别包useMemoadvanced-effect-event-deps.mduseEffectEvent返回的函数身份每次渲染都会变化绝不能放进依赖数组其中advanced-effect-event-deps与本规则形成两面本规则说依赖写原始值该规则则警告不要把身份刻意不稳定的事物Effect Event 函数写进依赖数组——两者本质一致都是在帮助 React 准确判断什么真的变了。给 Agent 的落地检查清单基于本规则可提炼出一份可直接复用的审查清单适合注入 Agent 的代码审查 / 重构提示词或人工自查扫描依赖数组useEffect依赖中是否有对象/数组/函数字面量effect 内是否只使用其中某个原始字段→ 收窄为obj.field。检查连续值依赖依赖是否是width、scrollY、searchParams这类连续变化值→ 在渲染期派生布尔值const isMobile width 768effect 依赖布尔值或改用useMediaQuery。检查派生状态effect 是否只是用setState复制 props/state 的可计算值→ 渲染期直接计算删除 state 与 effect参照rerender-derived-state-no-effect。检查交互副作用effect 是否在响应点击/提交/拖拽→ 移入事件处理器参照rerender-move-effect-to-event。检查订阅清理effect 是否注册了事件监听/WebSocket/HMR 订阅→ 必须返回清理函数依赖收窄为原始值参照 use-slide-module.ts。最后确认依赖是否既不多对象整体、无关状态也不不少漏掉实际读取的响应式值会触发 eslint exhaustive-deps 警告附注如 rerender-split-combined-hooks.md 所述若项目已启用 React Compiler它会自动优化依赖追踪部分场景可由编译器接管未启用时仍建议人工遵循本规则。小结rerender-dependenciesNarrow Effect Dependencies是 React 重渲染优化中性价比极高的一条规则把 effect 依赖从对象收窄到原始值并把连续值计算降级为布尔派生值即可显著减少 effect 的重跑次数与随之而来的不必要副作用。open-slide 的 use-media-query.ts、use-is-mobile.ts 与 use-slide-module.ts 从源码层面印证了这套模式在真实产品中的可落地性——这也正是面向 Agent 的性能优化技能所追求的效果规则可枚举、示例可比较、结论可验证。赞分享【免费下载链接】open-slideA slide framework built for agents.项目地址https://gitcode.com/gh_mirrors/op/open-slide点击查看免费下载相关推荐黑果配置快速指南OpCore Simplify 如何自动生成 OpenCore EFI 并装好 macOS黑果配置快速指南OpCore Simplify 如何自动生成 OpenCore EFI 并装好 macOS 如果你正在为黑苹果配置头疼——OpenCore E开发工具CLIZCode React 最佳实践Narrow Effect Dependencies收窄 Effect 依赖完全指南ZCode React 最佳实践Narrow Effect Dependencies收窄 Effect 依赖完全指南 ZCode 的前端构建于 ReactReact Effect 依赖收窄Narrow Effect Dependencies在 OpenMetadata 中最小化 useEffect 重跑的性能优化指南React Effect 依赖收窄Narrow Effect Dependencies在 OpenMetadata 中最小化 useEffect 重跑的性数据目录数据血缘数据治理后端MCP 服务上一篇5个核心技术要点深度解析安卓虚拟摄像头实现原理与实战应用下一篇10分钟免费教程用Blender化学插件快速实现专业分子可视化创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考