NextJS 13:路由跳转后用户列表数据未重新获取问题求助
解决Next.js删除用户后列表页缓存不更新的问题
我在用户详情页(路由:/users/[username])添加了删除用户按钮,点击后调用删除用户API,接着执行router.push('/users')跳转到用户列表页,但列表页的数据被缓存,没有重新获取最新内容。
初始代码
删除按钮组件(DeleteUserButton)
"use client" import deleteUser from "@/lib/users/deleteUser" import { revalidatePath } from "next/cache" import { useRouter } from 'next/navigation' type Props = { user: User } export default function DeleteUserButton({ user }: Props) { const router = useRouter() const deleteUserCallback = async (id: string) => { deleteUser(id) .then(() => { router.push("/users") }) } return ( <button type="button" onClick={() => deleteUserCallback(user.id)}> Delete </button> ) }
用户详情页(/users/[username])
import getUserByUsername from "@/lib/users/getUserByUsername" import DeleteUserButton from "./components/DeleteUserButton" type Props = { params: { username: string } } export async function generateMetadata({ params: { username } }: Props) { const user = await getUserByUsername(username) if (user === null) { return { title: "User not found", } } return { title: `${user.lastName} ${user.firstName}`, } } export default async function UserPage({ params: { username } }: Props) { const user = await getUserByUsername(username) if (user === null) { return <div>User not found</div> } return ( <div> <p>User: {user.email}</p> <DeleteUserButton user={user} /> </div> ) }
用户列表页(/users)
import getUsers from "@/lib/users/getUsers" import Link from "next/link" export default async function UsersPage() { const usersReq = await getUsers() const users = usersReq.users return ( <div> {users.map((user) => { return ( <p key={user.id}> <Link href={`/users/${user.username}`}> {user.username} </Link> {user.firstName} </p> ) })} </div> ) }
初始getUsers函数
export default async function getUsers(): Promise<{ users: User[], pagination: Pagination }> { const res = await fetch(process.env.NEXT_PUBLIC_API_BASE_URL + '/users?pageSize=20', { cache: 'no-cache', }); if (!res.ok) throw new Error('Error fetching'); return res.json(); }
尝试修改后出现的问题
我尝试给getUsers添加缓存标签,并用revalidateTag刷新缓存,但点击删除按钮后控制台报错:Error: Invariant: static generation store missing in revalidateTag
修改后的getUsers函数
export default async function getUsers(): Promise<{ users: User[], pagination: Pagination }> { const res = await fetch(process.env.NEXT_PUBLIC_API_BASE_URL + '/users?pageSize=20', { cache: 'no-cache', next: { tags: ['users'] } }); if (!res.ok) throw new Error('Error fetching'); return res.json(); }
修改后的DeleteUserButton组件
"use client" import deleteUser from "@/lib/users/deleteUser" import { revalidateTag } from "next/cache" import { useRouter } from 'next/navigation' type Props = { user: User } export default function DeleteUserButton({ user }: Props) { const router = useRouter() const deleteUserCallback = async (id: string) => { deleteUser(id) .then(() => { revalidateTag("users") router.push("/users") }) } return ( <button type="button" onClick={() => deleteUserCallback(user.id)}> Delete </button> ) }
解决方案
问题出在cache: 'no-cache'和next.tags的冲突上,no-cache强制每次请求重新获取数据,和缓存标签机制不兼容。另外,异步逻辑的处理也需要调整。
方案一:修复缓存标签的使用
- 调整getUsers的缓存策略:移除
cache: 'no-cache',保留缓存标签:
export default async function getUsers(): Promise<{ users: User[], pagination: Pagination }> { const res = await fetch(process.env.NEXT_PUBLIC_API_BASE_URL + '/users?pageSize=20', { next: { tags: ['users'] } }); if (!res.ok) throw new Error('Error fetching'); return res.json(); }
- 修复DeleteUserButton的异步逻辑:用
async/await替代then,确保操作顺序正确:
"use client" import deleteUser from "@/lib/users/deleteUser" import { revalidateTag } from "next/cache" import { useRouter } from 'next/navigation' type Props = { user: User } export default function DeleteUserButton({ user }: Props) { const router = useRouter() const deleteUserCallback = async (id: string) => { try { await deleteUser(id) await revalidateTag("users") router.push("/users") } catch (err) { console.error('删除用户失败:', err) } } return ( <button type="button" onClick={() => deleteUserCallback(user.id)}> Delete </button> ) }
方案二:直接使用revalidatePath(更简单)
如果标签方式仍有问题,可以直接指定刷新列表页路径,无需修改getUsers:
"use client" import deleteUser from "@/lib/users/deleteUser" import { revalidatePath } from "next/cache" import { useRouter } from 'next/navigation' type Props = { user: User } export default function DeleteUserButton({ user }: Props) { const router = useRouter() const deleteUserCallback = async (id: string) => { try { await deleteUser(id) revalidatePath("/users") router.push("/users") } catch (err) { console.error('删除用户失败:', err) } } return ( <button type="button" onClick={() => deleteUserCallback(user.id)}> Delete </button> ) }
内容的提问来源于stack exchange,提问作者LoisDuplain
相关产品推荐
相关产品推荐

