尧图精选

Next.js Server Action 中刷新当前页面的标准做法:next/cache 的 refresh() 实践

🕒 发布时间:2026/9/7 7:38:35 📁 来源:尧图网络
Next.js Server Action 中刷新当前页面的标准做法next/cache 的 refresh() 实践【免费下载链接】next.jsThe React Framework项目地址: https://gitcode.com/GitHub_Trending/next/next.js本文围绕一个具体的工程任务展开创建一个 Server Action 来切换用户的通知偏好开/关并在切换完成后不跳转页面地刷新当前页面让最新偏好立即可见。这个场景是 App Router 下最典型的服务端变更后同步 UI需求。读完后你将掌握 Next.js 推荐的refresh()来自next/cache的正确用法、它在源码层面的约束与实现原理以及如何规避redirect()到当前页、客户端router.refresh()等常见反模式。本仓库中该任务由评测用例 evals/evals/agent-038-refresh-settings/PROMPT.md 及其验收测试 EVAL.ts 完整定义。任务定义切换通知偏好后无跳转刷新任务文档 PROMPT.md 给出了明确的要求原文要点创建一个Server Action用于切换用户的通知偏好on/off切换完成后当前页面应刷新以显示更新后的偏好且不得重定向到其他页面必须使用Next.js 推荐的方式在 Server Action 内部刷新当前页面。配套的初始页面 app/page.tsx 只是一个占位组件提示Please implement a notification toggle with server-side refresh项目依赖声明在 package.json 中为next: ^16、react: 19.1.0即该实践基于 App Router 的 Server Components / Server Actions 模型。这个任务看似简单但存在多条看似可行、实则不推荐的路线验收测试会逐一拦截。验收标准什么样的实现才算正确EVAL.ts 通过静态扫描项目中的所有.ts/.tsx文件来判定实现是否合格其测试注释直接点明了难点原文Tricky because agents use redirect() to the same page (loses scroll/state), return data for manual refresh, or use client-side router.refresh().具体断言可归纳为五条硬标准断言检查内容对应测试服务端导入存在import ... refresh ... from next/cacheServer Action imports refresh from next/cache服务端指令相关文件包含use server或use serverServer Action uses use server directive正确调用同一文件既有use server又调用了refresh()正则refresh\s*\(\s*\)Server Action calls refresh() for page refresh禁止客户端刷新必须使用服务端next/cache的refresh而非useRouter().refresh()Does NOT use router.refresh() from client业务逻辑完整含use server的文件中存在 notification / toggle / preference / setting 相关逻辑Server Action has notification/toggle logic此外EVAL.ts 第 93-106 行的测试Does NOT use redirect for same-page update专门针对用redirect()跳回当前 URL这类做法——它会导致滚动位置和表单状态丢失是同一页面更新的错误方案。从源码结构看这三类被否决的方案各自的问题在于redirect(currentUrl)触发完整导航页面状态滚动位置、输入草稿全部丢失Server Action 返回数据、由客户端手动更新状态把刷新的责任从框架层转移到了每个页面组件无法保证所有数据源一致失效客户端router.refresh()绕过了 Server Action 的服务端上下文客户端发起的刷新无法携带本次变更的服务端语义。官方 APIrefresh()的规格与约束Next.js 官方文档 docs/01-app/03-api-reference/04-functions/refresh.mdx 对refresh的定义非常精简但关键用途允许你在 Server Action 内部刷新客户端路由client router签名refresh(): void不接收参数不返回任何值唯一合法上下文只能在 Server Action 中调用。不能在 Route Handler、客户端组件或任何其他上下文中使用在 Route Handler 中调用的后果文档给出的反例app/api/posts/route.ts中调用refresh()会直接抛出运行时错误。官方文档的标准示例TypeScript 版app/actions.tsuse server import { refresh } from next/cache export async function createPost(formData: FormData) { const title formData.get(title) const content formData.get(content) // Create the post in your database const post await db.post.create({ data: { title, content }, }) refresh() }其 JavaScript 版本app/actions.js写法相同仅去除类型注解。官方文档同时注明了refresh的关联文档为 App Router 的 Server Actions 指南。源码剖析refresh()如何生效refresh的真正实现位于 packages/next/src/server/web/spec-extension/revalidate.ts而next/cache模块只是从该路径将其重新导出——在 packages/next/src/server/lib/router-utils/cache-life-type-utils.ts 生成的类型定义中可以看到updateTag、revalidateTag、revalidatePath、refresh均来自next/dist/server/web/spec-extension/revalidate。实现代码本身只有两层逻辑// packages/next/src/server/web/spec-extension/revalidate.ts export function refresh() { const workStore workAsyncStorage.getStore() const workUnitStore workUnitAsyncStorage.getStore() if ( !workStore || workStore.page.endsWith(/route) || // 排除 Route Handler workUnitStore?.phase ! action // 必须是 action 阶段 ) { throw new Error( refresh can only be called from within a Server Action. See more info here: https://nextjs.org/docs/app/api-reference/functions/refresh ) } if (workStore) { // The Server Action version of refresh() only revalidates the dynamic // data on the client. It doesnt affect cached data. workStore.pathWasRevalidated ActionDidRevalidateDynamicOnly } }可以从中读出三个关键事实上下文守卫通过workAsyncStorage/workUnitAsyncStorage两个 AsyncLocalStorage 读取当前工作单元若不在phase action的 Server Action 中、或当前是/route文件立即抛错。这与文档中只能从 Server Action 调用的约束一一对应只失效动态数据注释明确说明 Server Action 版本的refresh()只让客户端缓存的动态数据失效不影响静态缓存数据源码常量ActionDidRevalidateDynamicOnly即此语义定义于packages/next/src/shared/lib/action-revalidation-kind.ts作用机制它不是发起一次新的服务端请求而是在当前响应的 work store 上打一个pathWasRevalidated标记框架在响应回程时据此让客户端重新拉取当前页面的动态数据从而完成无跳转刷新。对照同文件中revalidateTag/revalidatePathrevalidate.ts#L33-L46、revalidate.ts#L106-L132可知那些函数走revalidate()路径写入store.pendingRevalidatedTags以失效服务端数据缓存而refresh()走的是完全不同的轻量路径只标记客户端动态数据。这正是切换偏好后立即看到新值所需的精确语义。完整可运行示例通知偏好切换结合任务要求与官方示例风格一个满足全部验收标准的完整实现如下TypeScript适用于评测项目 evals/evals/agent-038-refresh-settings/ 的 Next.js 16 / React 19.1 环境// app/page.tsx import { toggleNotifications } from /app/actions type PageProps { notificationsEnabled: boolean } export default async function SettingsPage({ notificationsEnabled }: PageProps) { return ( main h1Settings/h1 p Notifications are currently{ } strong{notificationsEnabled ? ON : OFF}/strong. /p {/* action 直接绑定 Server Action提交即触发服务端切换 刷新 */} form action{toggleNotifications} button typesubmit {notificationsEnabled ? Disable : Enable} notifications /button /form /main ) }// app/actions.ts use server import { refresh } from next/cache // 此处替换为真实的持久化逻辑数据库、KV 等 let notificationsEnabled true export async function toggleNotifications() { notificationsEnabled !notificationsEnabled // 关键一步让当前页面的动态数据在服务端变更后失效 // 客户端将自动重取当前页面无需 redirect、不丢滚动状态 refresh() }实现要点对照use server指令 独立文件中的导出异步函数符合 Server Action 定义import { refresh } from next/cache且在同一文件内调用refresh()满足 EVAL.ts 第 41-91 行的三条断言导入、指令、调用文件名含actions、函数名含toggle/Notifications语义满足notification/toggle logic断言全程无redirect()、无useRouter().refresh()。常见反模式与适用边界结合验收测试与源码行为总结如下表做法是否推荐原因Server Action 内调用refresh()next/cache推荐框架级无跳转刷新保留滚动与表单状态动态数据一致失效redirect(currentUrl)回当前页不推荐触发完整导航丢失滚动位置与页面状态EVAL.ts 明确拦截Server Action 返回数据、客户端手动 setState不推荐刷新逻辑分散到各组件无法保证所有动态数据源同步失效客户端router.refresh()不推荐绕开 Server Action 的服务端变更语义在 Route Handler 中调用refresh()运行时报错源码守卫直接抛出 refresh can only be called from within a Server Action适用前提与限制需要说明清楚refresh()依赖 App Router 的 Server Actions 运行时workUnitStore.phase action因此只适用于 App Router 项目它失效的是客户端侧动态数据若你的变更还写入了带 tag 的服务端缓存如通过unstable_cache或 Cache Components 的数据应配合updateTag或revalidateTag使用见同文件 revalidate.ts 中两者的实现差异。对于切换开关后立即看到新值这类纯动态读取的场景单独使用refresh()即是最小且正确的方案。【免费下载链接】next.jsThe React Framework项目地址: https://gitcode.com/GitHub_Trending/next/next.js创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联 返回资讯列表 →