简体   繁体   中英

Nextjs dynamic routes issue - dynamic routes not displaying proper content

I have this [id].js dynamic route inside user folder. I'm using getStaticPaths in order to statically pre render these paths, then using getStaticProps to fetch for the data for each page.

However, when in production (since these functions run on every request while in development mode, so the problem doesn't exist there), when navigating between for example: /user/a to /user/b , it keeps showing /user/a data.

I'm also using react-query . I'm aware I could fix this issue by just refreshing the data on the client side whenever the route changes but now I ask: Shouldn't this be the default/expected behavior when creating dynamic routes using getStaticPaths and getStaticProps ?

This happens with all dynamic routes, here's 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;

Edit: useData custom hook:

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 };
};

You need to include the userId in the queryKey. Otherwise, all requests write to the same cache entry. The React Query Devtools should show you this.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM