Nextjs 动态路由问题 - 动态路由未显示正确的内容

Nextjs dynamic routes issue - dynamic routes not displaying proper content

我在 user 文件夹中有这个 [id].js 动态路由。我正在使用 getStaticPaths 来静态预呈现这些路径,然后使用 getStaticProps 来获取每个页面的数据。

但是,在生产环境中(因为这些功能 运行 在开发模式下的每个请求上,所以问题不存在),例如在 /user/a/user/b,它一直显示 /user/a 数据。

我也在使用 react-query。我知道我可以通过在路由更改时刷新客户端的数据来解决这个问题,但现在我问:这不应该是使用 getStaticPaths 和创建动态路由时的 default/expected 行为吗? getStaticProps?

所有动态路由都会发生这种情况,这里是 user:

import React from "react";
import Image from "next/image";
import { dehydrate, QueryClient } from "react-query";
import { Layout, Posts } from "../../components";
import {
  postsByUserQuery,
  userQuery,
  usersQuery,
  postsSavedByUserQuery,
} from "../../utils/data";
import {
  fetchPostsByUser,
  fetchUser,
  fetchPostsSavedByUser,
} from "../../utils/fetchers";
import { useData } from "../../hooks/useData";
import { client } from "../../client/client";
import { useRouter } from "next/router";
import { useSession, signOut } from "next-auth/react";

const UserProfile = () => {
  const router = useRouter();
  const { id } = router.query;
  const { data: session } = useSession();

  const { data: user } = useData("userInfo", fetchUser, id);

  const {
    data: postsByUser,
    isFetching: isFetchingPostsByUser,
    refetch: refetchPostsByUser,
  } = useData("postsByUser", fetchPostsByUser, id);

  const {
    data: postsSavedByUser,
    isFetching: isFetchingPostsSavedByUser,
    refetch: refetchPostsSavedByUser,
  } = useData("postsSavedByUser", fetchPostsSavedByUser, id);

  return (
    <Layout
      title={`PostIt | ${user[0]?.userName} Profile`}
      ogUrl={process.env.NEXT_PUBLIC_BASEURL + router.asPath}
      ogType="article"
    >
      <div className="relative w-full h-[250px] 2xl:h-[350px]">
        <Image
          layout="fill"
          placeholder="blur"
          blurDataURL={`https://source.unsplash.com/1600x900/?${postsByUser[0]?.category}`}
          src={`https://source.unsplash.com/1600x900/?${postsByUser[0]?.category}`}
          alt="user-Cover-Pic"
          objectFit="cover"
          priority
        />
      </div>
      <section className="flex flex-col w-full gap-5 px-4 py-12 mx-auto max-w-7xl md:px-8 lg:px-10">
        <div className="flex flex-col justify-center items-center gap-8">
          <h1 className="text-center text-2xl 2xl:text-4xl text-white font-bold">
            {user[0]?.userName}
          </h1>
          <div className="ring-2 ring-gray-100 p-1 flex items-center justify-center rounded-full w-60 h-60 2xl:w-80 2xl:h-80">
            <div className="relative w-full h-full">
              <Image
                src={user[0]?.image}
                layout="fill"
                className="rounded-full"
                alt="User Avatar"
                objectFit="cover"
              />
            </div>
          </div>
          {user[0]?._id === session?.user?.uid && (
            <div className="w-full flex items-center justify-center">
              <button
                type="button"
                className="mt-2 w-full max-w-[120px] rounded-lg text-base 2xl:text-lg text-white font-bold border-none outline-none bg-red-500 p-2 flex items-center justify-center transition duration-150 hover:bg-red-700"
                onClick={() => signOut({ callbackUrl: "/login" })}
              >
                Logout
              </button>
            </div>
          )}
          <div className="flex flex-col gap-2 mt-5 w-full">
            <span className="text-white text-base 2xl:text-xl font-bold">
              Posts by {user[0]?.userName}{" "}
              {postsByUser?.length > 0 ? `(${postsByUser.length})` : `(0)`}
            </span>
            {postsByUser?.length > 0 ? (
              <Posts
                posts={postsByUser}
                refresh={refetchPostsByUser}
                isFetching={isFetchingPostsByUser}
              />
            ) : (
              <p className="text-sm 2xl:text-lg text-gray-400 w-full">
                This user has not posted anything yet.
              </p>
            )}
          </div>
          <div className="flex flex-col gap-2 mt-5 w-full">
            <span className="text-white text-base 2xl:text-xl font-bold">
              Saved by {user[0]?.userName}{" "}
              {postsSavedByUser?.length > 0
                ? `(${postsSavedByUser.length})`
                : `(0)`}
            </span>
            {postsSavedByUser?.length > 0 ? (
              <Posts
                posts={postsSavedByUser}
                refresh={refetchPostsSavedByUser}
                isFetching={isFetchingPostsSavedByUser}
              />
            ) : (
              <p className="text-sm 2xl:text-lg text-gray-400 w-full">
                This user has not saved any post yet.
              </p>
            )}
          </div>
        </div>
      </section>
    </Layout>
  );
};

export async function getStaticPaths() {
  const query = usersQuery();
  const users = await client.fetch(query);

  const paths = users.map((user) => ({
    params: { id: user._id },
  }));

  return {
    paths,
    fallback: false,
  };
}

export async function getStaticProps({ params }) {
  const queryClient = new QueryClient();
  const user = userQuery(params.id);
  const postsByUser = postsByUserQuery(params.id);
  const postsSavedByUser = postsSavedByUserQuery(params.id);

  await queryClient.prefetchQuery("userInfo", () =>
    client.fetch(user).then((data) => data)
  );

  await queryClient.prefetchQuery("postsByUser", () =>
    client.fetch(postsByUser).then((data) => data)
  );

  await queryClient.prefetchQuery("postsSavedByUser", () =>
    client.fetch(postsSavedByUser).then((data) => data)
  );

  return {
    props: {
      dehydratedState: dehydrate(queryClient),
    },
    revalidate: 30,
  };
}

export default UserProfile;

编辑: useData 自定义挂钩:

import { useQuery } from "react-query";
import { toast } from "react-toastify";

export const useData = (queryKey, queryFn, queryFnParam1, queryFnParam2) => {
  const { data, isFetching, refetch } = useQuery(
    queryKey,
    () => queryFn(queryFnParam1, queryFnParam2),
    {
      staleTime: 2.5 * 60 * 1000, //2.5 minutes
      onError: (error) => {
        toast.error(
          `Couldn't establish connection due to error: ${error.message}`
        );
      },
    }
  );

  return { data, isFetching, refetch };
};

您需要在 queryKey 中包含 userId。否则,所有请求都写入同一个缓存条目。 React Query Devtools 应该会告诉你这个。