Next.js Discord

Discord Forum

Avoid Re-fetching shared data

Answered
Polish posted this in #help-forum
Open in Discord
Avatar
PolishOP
I have the following setup

/profile/[id]
page.js - server
gets [id] and passes it to client component content.js (shared)
content.js fetchs profile data and renders profile card (shared)

/profile/[id]/following
page.js - server
gets [id] and passes it to client component content.js (shared)
content.js fetchs profile data and renders profile card (shared)
Tab renders section for people they are following
Tab fetchs following specific api data

/profile/[id]/followers
page.js - server
gets [id] and passes it to client component content.js (shared)
content.js fetchs profile data and renders profile card (shared)
Tab renders section for people who are following them
Tab fetchs followers specific api data

The issue is since all 3 routes are using the shared content.js all route navigations are refetching the profile data. Is there any way to improve my code so profile data api isn't constantly being refetched
Answered by adam.birds
The provider is the way forward. Here is an example of my auth provider which also fetches user data etc:

https://github.com/adb-software-solutions/debuglife/blob/main/debuglife-frontend/src/context/AuthContext.tsx

And then I can just import useAuth anywhere to access the user data.
View full answer

25 Replies

Avatar
PolishOP
Also the shared profile data is fetched using useEffect
Avatar
Round sardinella
You should look into React Query. This sort of issue is one of the main focuses of that library.
https://tanstack.com/query/latest/docs/framework/react/overview
Instead of querying inside a useEffect, React Query provides hooks where you define your data fetching logic and unique keys that determine if a query should be refetched.
The data returned by each query is cached using the unique key you provide and can be manually refetched if needed.
Avatar
Round sardinella
Without third party code, you'd just have to set up a context to be shared across your component tree
Avatar
@Round sardinella Without third party code, you'd just have to set up a context to be shared across your component tree
Avatar
PolishOP
Could you provide an example of how context would be implemented? I don't want the data cached per say. So like if the page is reloaded refetching is fine. Just want to avoid the refetching during navigation
Avatar
Cape lion
Im not sure if i understand the problem correctly, but cant you move profile data fetching to layout.tsx and pass it down as prop?
Avatar
@Cape lion Im not sure if i understand the problem correctly, but cant you move profile data fetching to layout.tsx and pass it down as prop?
Avatar
PolishOP
Maybe? How does that get passed down to the children?
export default function RootLayout({ children }) {
  return (
    <div>{children}</div>
  );
}
Avatar
Cape lion
I think the only way would be to use createElement...
but as i read
Using cloneElement is uncommon and can lead to fragile code.


so as @Round sardinella said,
i think you need to create provider in layout

export default async function ProfileLayout({ children, params }) {
  const { id } = params;
  const profileData = await fetchProfileData(id);

  return <ProfileProvider profileData={profileData}>{children}</ProfileProvider>;
}


but im not 100% sure about it 😅
Avatar
Round sardinella
With React context, you create and define a context in a provider component and any children of that component can access it with useContext
Avatar
Cape lion
Avatar
The provider is the way forward. Here is an example of my auth provider which also fetches user data etc:

https://github.com/adb-software-solutions/debuglife/blob/main/debuglife-frontend/src/context/AuthContext.tsx

And then I can just import useAuth anywhere to access the user data.
Answer
Avatar
@Cape lion Why does it need to be client side?
Avatar
PolishOP
1. Nature of the API
2. Performance
Avatar
Australian Freshwater Crocodile
Do you want to avoid making the request (network) or you want to avoid repeating the getDataFunction() logic everywhere?

There’s different approaches depending on what you need/try to achieve.

If what you want is avoid is to make several requests when you know for a fact they’re all gonna be the same call then wrap your fetching function (either it’s a Database call, fetch, whatever) in Next.js unstable_cache (that’s actually pretty stable lol).

If you want to keep the components clean and it’s gonna be all client anyway then use context and abstract the logic to a custom hook.

If all you want is having access to the params in the client side just use useParams().
There’s no such thing as Context in the server side tho, if you put something in Context you’ll only be able to access it on client components
And also if you’re using React 19, if you’re doing the fetching on mount inside a use Effect you could instead trigger the fetching promise in the server component (page.js) and pass the promise down to the client component, then access to the promise value with the hook use(promise).
This will suspend your component while it’s waiting for the data and you can wrap it in suspense for a nice loading state.

If this fetcher function is wrapped in unstable_cache and it’s called in a different component and it’s already solved then it’ll be instantly