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.