You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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强制每次请求重新获取数据,和缓存标签机制不兼容。另外,异步逻辑的处理也需要调整。

方案一:修复缓存标签的使用

  1. 调整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();
}
  1. 修复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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 08:54:50