Next.js Beta版Mutation问题:router.refresh()未刷新服务端数据
问题分析与解决
你的问题出在两个核心点上:
1. 服务端数据被缓存,router.refresh()未触发真实请求
Next.js 中 fetch 默认对 GET 请求启用缓存机制,你的getCategories函数调用第三方 API 时未指定缓存策略,导致每次调用都会复用缓存数据,所以router.refresh()后服务端并没有重新请求新数据,id自然不会更新。
2. 客户端组件本地状态未同步服务端新props
你的Test组件用useState初始化了本地状态todo,但useState的初始值仅在组件首次挂载时生效。当服务端组件重新渲染并传递新的id给Test时,本地状态不会自动更新,所以你看到的还是之前客户端设置的id。
解决方案
步骤1:修改服务端fetch的缓存策略
在getCategories的fetch请求中添加cache: 'no-store',强制每次请求都从服务器获取新数据:
export async function getCategories() { try { const res = await fetch("https://random-data-api.com/api/v2/banks?size=1", { cache: 'no-store' // 禁用缓存,每次请求都获取新数据 }); if (res.status === 200) { // 直接使用状态码200,避免未定义的ResponseStatusCode报错 const data = await res.json(); return data; } } catch (error) { console.log(error); } }
步骤2:让客户端组件同步服务端props的变化
在Test组件中添加useEffect,监听props.id的变化,更新本地状态todo:
"use client"; import { useRouter } from "next/navigation"; import { useState, useTransition, useEffect } from "react"; interface Todo { id: number; } export const Test = (props: Todo) => { const router = useRouter(); const [isPending, startTransition] = useTransition(); const [isFetching, setIsFetching] = useState(false); const [todo, setTodo] = useState<any>(props.id); // 监听props.id变化,同步更新本地状态 useEffect(() => { setTodo(props.id); }, [props.id]); const isMutating = isFetching || isPending; async function handleChange() { setIsFetching(true); const response = await fetch( `https://random-data-api.com/api/v2/users?size=1`, { method: "GET", } ); setIsFetching(false); const data = await response.json(); setTodo(data.id); startTransition(() => { router.refresh(); }); } return <button onClick={handleChange}>{todo}</button>; };
修改后流程:
- 点击按钮后客户端先更新本地状态显示临时id
router.refresh()触发服务端组件重新渲染,getCategories重新请求API获取新的服务端id- 服务端将新id传给
Test组件,useEffect监听到props变化,同步更新本地状态为服务端的新id
内容的提问来源于stack exchange,提问作者bappp
相关产品推荐
相关产品推荐

