拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Langfuse 前端实战:遵循 Vercel 最佳实践,在渲染期间计算派生状态而非存入 state/effect

Langfuse 前端实战遵循 Vercel 最佳实践在渲染期间计算派生状态而非存入 state/effect【免费下载链接】langfuse Open source AI engineering platform: LLM evals, observability, metrics, prompt management, playground, datasets. Integrates with OpenTelemetry, LangChain, OpenAI SDK, LiteLLM, and more. YC W23项目地址: https://gitcode.com/GitHub_Trending/la/langfuse派生状态Derived State是 React 重渲染优化中最容易踩坑、也最容易修复的一类问题。Langfuse 仓库内置的 Vercel React 最佳实践规则集web/.agents/skills/vercel-react-best-practices/将在渲染期间计算派生状态而不是用 useState useEffect 去同步列为 Re-render Optimization 类别MEDIUM 影响级别的核心规则用于指导前端组件的编写、评审与自动化重构。读完本文你将掌握识别冗余 state effect 同步反模式的方法、写出零额外渲染的派生状态代码并理解 Langfuse 前端源码中真实运用该规则如 score-tag 的 level 派生的具体形态。规则概述一条来自 Vercel Engineering 的派生状态守则本规则来源于 Langfuse 仓库中的规则文件 rerender-derived-state-no-effect.md其核心表述非常精炼如果一个值可以从当前的 props/state 计算得出就不要把它存入 state也不要在 effect 中去更新它。应在渲染期间直接派生它以避免额外的渲染和状态漂移state drift。不要仅仅为了响应 prop 变化而在 effect 中设置 state应优先使用派生值或 keyed reset基于 key 的重置方案。该规则在 SKILL.md 中被归入Re-render Optimization重渲染优化MEDIUM 优先级类别impact 描述为avoids redundant renders and state drift避免冗余渲染与状态漂移标签为rerender、derived-state、useEffect、state。整个规则集由 Vercel Engineering 维护、以 MIT 许可发布共 57 条规则、覆盖 8 大类别本规则属于其中rerender-前缀的 12 条重渲染优化规则之一。在聚合文档 AGENTS.md 的第 5.1 节中该规则被列为 Re-render Optimization 章节的第一条。反模式剖析冗余 state effect 同步为什么会出问题规则文件给出了最经典的错误示例——用useState存fullName再用useEffect在firstName/lastName变化时同步更新它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 }这段代码看似顺理成章但至少埋下了三类问题额外的一次渲染当firstName改变时React 先渲染一次此时fullName还是旧值effect 执行后又setFullName触发第二次渲染。每次输入变化都白多渲染一遍组件在表单、表格这类高频交互场景中会被成倍放大。状态漂移state drift风险fullName是独立的一份 state它的正确性依赖 effect 是否在所有相关 state 变化时都正确触发。一旦漏写依赖、或者有第三条修改路径例如直接setFullName与表单输入并存state 就会与真实输入脱节出现显示的值和输入不一致这类最难排查的 bug。不必要的 effect 开销effect 本身的注册、依赖比对、执行与清理都有成本而这里执行的操作字符串拼接根本没有副作用完全不需要 effect 的副作用时机语义。正确姿势把派生计算直接写进渲染过程规则文件给出的正确版本堪称教科书式的删代码式优化——去掉 state、去掉 effect、去掉 setter只保留一次渲染期的计算function Form() { const [firstName, setFirstName] useState(First) const [lastName, setLastName] useState(Last) const fullName firstName lastName return p{fullName}/p }对比之下可以清晰看到本规则的方法论任何由现有数据推导而来、且不参与持久化的值都不应该是 state。fullName在每次渲染时都是firstName与lastName的确定函数派生计算随渲染自动重跑天然保证与输入同步永远不存在漂移firstName变化时 React 只渲染一次fullName直接就是新值。这条规则的底层原理值得展开React 的函数组件本质上是一个props/state → UI的纯函数。渲染期派生意味着派生逻辑与渲染同生命周期——输入变化 → 重渲染 → 派生值随之重算中间没有任何异步或时机问题。而useState引入的是需要跨渲染保留的记忆值useEffect引入的是渲染之外的副作用时机。把纯计算塞进这两者等于用状态机去模拟一个普通函数调用既慢又容易出错。适用范围判断什么时候该派生什么时候必须存 state规则强调如果一个值可以从当前 props/state 计算得出言下之意是不能计算得出的值才需要存 state。判据可以归纳为以下三点场景是否应存入 state理由可由 props/state 直接推导如firstName lastName否渲染期派生派生即同步无额外渲染来自异步请求或外部系统如 API 返回的列表、WebSocket 消息是无法从当前 state 计算得出需要跨渲染保存仅初始化一次、后续不再重算如从 localStorage 读取的初始配置是但用惰性初始化见rerender-lazy-state-init规则关于仅为了响应 prop 变化而在 effect 中同步 state的替代方案规则原文点明了两个方向优先派生如果目标值能被计算出来直接用渲染期派生如上面的fullName。keyed reset如果组件内部确实有一整套内部状态需要在 prop 变化时整体重置的需求更优雅的做法是用 React 的key机制——在父组件渲染时给子组件传入一个随 prop 变化的keyReact 会直接销毁并重建子组件其内部所有 state 自然归零完全不需要 effect 去逐字段同步。例如切换用户时ProfileForm key{userId} user{user} /userId变化即触发表单整体重建。此外还有一类容易混淆的场景需要澄清在渲染期间派生不等于在渲染期间修改 state。直接在渲染函数体中调用setState是明确的错误React 会抛出 Cannot update a component while rendering a different component 或导致死循环正确做法是像示例那样用普通表达式计算局部变量或在需要根据 props 调整 state 时采用渲染期间调用 setter 但设置器函数形式返回原值的官方「调整 state」模式以及上述 keyed reset。Langfuse 仓库中的真实实践佐证规则并不只是纸面教条Langfuse 前端代码中就能找到本规则思想的落地形态。以web/src/components/score-tag.tsx为例export const scoreLevelFromScore (score: { observationId?: string | null; traceId?: string | null; sessionId?: string | null; datasetRunId?: string | null; }): ScoreLevel score.observationId ! null ? observation : score.traceId ! null ? trace : score.sessionId ! null ? session : score.datasetRunId ! null ? experiment : trace;源码注释明确写道Stored scores carry no explicit level field — level is derived from which context id is set存储的 score 不携带显式 level 字段——level 由哪个 context id 被设置来派生。也就是说Langfuse 的数据模型刻意不把level冗余存入 state而是在渲染时通过scoreLevelFromScore这一纯函数从observationId/traceId/sessionId/datasetRunId现算出来。这正是本规则能从现有数据推导就不另存一份思想的直接体现——如果每个 score 都额外维护一份 level state 并用 effect 同步不仅多渲染还会在数据来源变化时产生漂移。再如web/src/hooks/use-environment-filter-options-cache.tsx该 Hook 内部使用useMemo如Object.entries(store).filter(([, value]) value.expiresAt now)这类派生计算而非把过滤结果同步进 effect与规则族中派生计算留在渲染过程的思路一脉相承。这类数据层派生 渲染期计算的模式在 Langfuse 的表格、过滤器、图表组件中被广泛使用。与相邻规则的协同一套完整的重渲染优化矩阵本规则不是孤立存在它与rerender-前缀下的一众规则共同构成重渲染优化矩阵理解它们之间的分工有助于在实际重构中一次改对rerender-derived-state.mdSubscribe to Derived State针对订阅连续值的问题主张订阅派生后的布尔值而非原始连续值例如用useMediaQuery((max-width: 767px))取代每个像素都触发重渲染的useWindowWidth()。与本规则互补——本规则解决值要不要存 state该规则解决订阅粒度如何选择。rerender-dependencies.mdNarrow Effect Dependencies当 effect 无法避免时依赖应窄化为原始类型[user.id]而非[user]并建议派生布尔值在 effect 外计算。例如用const isMobile width 768再依赖[isMobile]避免[width]在 767、766、765…… 每像素都触发。rerender-lazy-state-init.mdLazy State Initialization真正需要初始化的 state把初始化函数传给useState(() buildSearchIndex(items))避免每次渲染都重复执行昂贵初始化。rerender-move-effect-to-event.mdPut Interaction Logic in Event Handlers由用户交互点击、提交触发的副作用应放在事件处理器里而不是建模成state effect否则 effect 会在无关变化时重复执行。四者合起来是一条清晰的决策链能派生的值 → 渲染期直接算本规则订阅类状态 → 订阅派生布尔值必须存的值 → 惰性初始化必须做的副作用 → 放进事件处理器。只有真正属于渲染后的异步副作用的操作才轮到useEffect出场。规则要点速查核心判据一句话能从 props/state 算出来的就不该是 state。三个必查信号组件里出现useState()useEffect(() setX(...), [deps])的镜像同步结构effect 依赖数组与 setter 目标几乎同名渲染结果依赖的中间值由 effect 而非表达式产生。两个替代方案优先渲染期派生需要整体重置内部状态时用key重建。不要做的为了省事把可派生值塞进 effect 同步额外渲染 状态漂移 依赖管理负担在渲染函数体内直接调用 setter。落地参考本规则细节见 rerender-derived-state-no-effect.md完整规则体系见 SKILL.md 与 AGENTS.md第 5.1 节Langfuse 前端源码可对照 score-tag.tsx 的scoreLevelFromScore派生函数与 use-environment-filter-options-cache.tsx 的渲染期派生实践。本规则的概念源头是 React 官方文档中的经典章节《You Might Not Need an Effect》你也许并不需要 Effect——它系统性地列举了不需要 effect的常见场景本规则正是其在派生状态这一细分场景下的可执行化、可自动化检查的落地版本。【免费下载链接】langfuse Open source AI engineering platform: LLM evals, observability, metrics, prompt management, playground, datasets. Integrates with OpenTelemetry, LangChain, OpenAI SDK, LiteLLM, and more. YC W23项目地址: https://gitcode.com/GitHub_Trending/la/langfuse创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门