How to fix, nextjs pages refetching data after certain time passed when using graphql
Unanswered
Red imported fire ant posted this in #help-forum
![Avatar](https://cdn.discordapp.com/embed/avatars/5.png)
Red imported fire antOP
I have this nextjs 14 project and every page using graphql to fetch the data. And i deployed it, after visiting some pages through the navbar menu page does load on the first as usual(which is correct i assume). And then i click on some other navbar menu items and go back to the one i have visited. This time it loads immediately, but sometimes(after certain time passed) and i revisit the page that i have already visited before, boom it refetches data. How do i fix this? is there any idea why this is happening.
42 Replies
![Avatar](https://cdn.discordapp.com/embed/avatars/2.png)
Black-throated Blue Warbler
need to see your fetch functions to determine how you are configuring the cacheing
"sometimes(after certain time passed) and i revisit the page that i have already visited before, boom it refetches data. "
Sounds like your cache is expiring š
Sounds like your cache is expiring š
![Avatar](https://cdn.discordapp.com/embed/avatars/5.png)
Red imported fire antOP
@Black-throated Blue Warbler thank you for the reply, here is my graphql-request configuration:
import { GraphQLClient } from "graphql-request";
import { cache } from "react";
import { getSdk } from "@/gql"; // graphql-codegen
const CACHE_TIME = 60 * 60 * 1000; // 1 hour in milliseconds
const client = new GraphQLClient(
${process.env.NEXT_PUBLIC_BACKEND_URL}/graphql,
{
fetch: cache(async (url, params) =>
fetch(url, { ...params, next: { revalidate: CACHE_TIME } }),
),
},
);
const sdk = getSdk(client);
export default sdk;
![Avatar](https://cdn.discordapp.com/embed/avatars/2.png)
Black-throated Blue Warbler
hmm, well first issue is your cache time calculation, i think next revalidate uses seconds not miliseconds
so just put 3600 if you want 1hr
you could try setting the revlaidate for all requests on layout or page with:
export const revalidate = 3600 // revalidate at most every hour
export const revalidate = 3600 // revalidate at most every hour
![Avatar](https://cdn.discordapp.com/embed/avatars/5.png)
Red imported fire antOP
but isn't
const revalidate = 3600
only work for GET request ?![Avatar](https://cdn.discordapp.com/embed/avatars/5.png)
Red imported fire antOP
@Black-throated Blue Warbler thing is i didnt add any revalidate or custom fetch or cache before and project acts as i described. So then i tried to add those to fix this
![Avatar](https://cdn.discordapp.com/embed/avatars/2.png)
Black-throated Blue Warbler
oh right.. graphql use post by default
![Avatar](https://cdn.discordapp.com/embed/avatars/5.png)
Red imported fire antOP
yeah, š¦ been struggling to find the solution to this
![Avatar](https://cdn.discordapp.com/embed/avatars/2.png)
Black-throated Blue Warbler
you have to setup your own cacheing most likely, i think you're on the right track but you need a function that tries to fetch the data from cache first
think you'd need a setup like this:
where it attempts fetching from your cache before firing the post request
const client = new GraphQLClient(
`${process.env.NEXT_PUBLIC_BACKEND_URL}/graphql`,
{
fetch: cache(async (url, params) => {
const cacheKey = JSON.stringify({ url, params });
const cachedResponse = getCachedResponse(cacheKey);
if (cachedResponse) {
return new Response(JSON.stringify(cachedResponse), { status: 200 });
}
const response = await fetch(url, { ...params, method: "POST" });
const data = await response.json();
setCachedResponse(cacheKey, data, CACHE_TIME);
return new Response(JSON.stringify(data), { status: 200 });
}),
}
);
where it attempts fetching from your cache before firing the post request
![Avatar](https://cdn.discordapp.com/embed/avatars/5.png)
Red imported fire antOP
Where do i save the cache in here ? like
setCachedResponse
![Avatar](https://cdn.discordapp.com/embed/avatars/2.png)
Black-throated Blue Warbler
Warning: Untested GPT response
import { GraphQLClient } from "graphql-request";
import { cache } from "react";
import { getSdk } from "@/gql"; // graphql-codegen
const CACHE_TIME = 60 * 60 * 1000; // 1 hour in milliseconds
// Create a cached fetch function
const cachedFetch = cache(async (url, params) => {
const cacheKey = JSON.stringify({ url, params });
const cachedResponse = getCachedResponse(cacheKey);
if (cachedResponse) {
return new Response(JSON.stringify(cachedResponse), { status: 200 });
}
const response = await fetch(url, { ...params, method: "POST" });
const data = await response.json();
setCachedResponse(cacheKey, data, CACHE_TIME);
return new Response(JSON.stringify(data), { status: 200 });
});
const client = new GraphQLClient(
`${process.env.NEXT_PUBLIC_BACKEND_URL}/graphql`,
{
fetch: cachedFetch,
}
);
const sdk = getSdk(client);
export default sdk;
// In-memory cache utility functions
const cacheStorage = new Map();
const getCachedResponse = (key) => {
const cached = cacheStorage.get(key);
if (!cached) return null;
const now = Date.now();
if (now > cached.expiry) {
cacheStorage.delete(key);
return null;
}
return cached.value;
};
const setCachedResponse = (key, value, ttl) => {
const now = Date.now();
cacheStorage.set(key, { value, expiry: now + ttl });
};
export { getCachedResponse, setCachedResponse };
![Avatar](https://cdn.discordapp.com/embed/avatars/5.png)
Red imported fire antOP
Wait a minute, so post request does not have params and url will be always same right ?
![Avatar](https://cdn.discordapp.com/embed/avatars/2.png)
Black-throated Blue Warbler
post request should have some params like the body, log it and see
![Avatar](https://cdn.discordapp.com/embed/avatars/5.png)
Red imported fire antOP
Sorry but don't know why, returning new instance of Response with data or just data directly giving some strange error :
Error: GraphQL Error (Code: 200): {"response":{"error":"{\"data\":{\"HomePageContent\":{\"data\":{\"attributes\":{\"seo\":
yes you are correct, params does have body, so then cachekey works
One thing i couldn't figure out is what structure of the data fetch is returning, it seems when i remove the fetch overriding line it worked fine. But when i add it back this strange error thrown
![Avatar](https://cdn.discordapp.com/embed/avatars/2.png)
Black-throated Blue Warbler
seems like its already json and doesn't need to be stringified
try
return new Response(data, { status: 200 });
![Avatar](https://cdn.discordapp.com/embed/avatars/5.png)
Red imported fire antOP
yup, tried that and still same
![Avatar](https://cdn.discordapp.com/embed/avatars/2.png)
Black-throated Blue Warbler
can i see your full code? are you throwing an error anywhere?
![Avatar](https://cdn.discordapp.com/embed/avatars/5.png)
Red imported fire antOP
import { GraphQLClient } from "graphql-request";
import { getSdk } from "@/gql";
const CACHE_TIME = 60 * 60 * 1000;
const cacheStorage = new Map();
const getCachedResponse = (key) => {
const cached = cacheStorage.get(key);
if (!cached) return null;
const now = Date.now();
if (now > cached.expiry) {
cacheStorage.delete(key);
return null;
}
return cached.value;
};
const setCachedResponse = (key, value, ttl) => {
const now = Date.now();
cacheStorage.set(key, { value, expiry: now + ttl });
};
const customFetch = async (url, params) => {
const cacheKey = JSON.stringify({ url, params });
const cachedResponse = getCachedResponse(cacheKey);
if (cachedResponse) {
return new Response(JSON.stringify(cachedResponse), { status: 200 });
}
const response = await fetch(url, { ...params, method: "POST" });
// Check if response is not ok
if (!response.ok) {
throw new Error(`Network response was not ok: ${response.statusText}`);
}
// Attempt to parse response data
const data = await response.json();
// Check for GraphQL errors
if (data.errors) {
console.error("GraphQL errors:", data.errors);
throw new Error(`GraphQL Error: ${JSON.stringify(data.errors)}`);
}
// Cache the response data
setCachedResponse(cacheKey, data, CACHE_TIME);
console.log("Set cache success");
return new Response(data, {status: 200});
};
const client = new GraphQLClient(
`${process.env.NEXT_PUBLIC_BACKEND_URL}/graphql`,
{
fetch: customFetch,
},
);
const sdk = getSdk(client);
export default sdk;
![Avatar](https://cdn.discordapp.com/embed/avatars/2.png)
Black-throated Blue Warbler
well right here is throwing that error:
// Check for GraphQL errors
if (data.errors) {
console.error("GraphQL errors:", data.errors);
throw new Error(`GraphQL Error: ${JSON.stringify(data.errors)}`);
}
instead of throwing the error just log it so we can read it
![Avatar](https://cdn.discordapp.com/embed/avatars/5.png)
Red imported fire antOP
I just checked and seems its not this error throwing
![Avatar](https://cdn.discordapp.com/embed/avatars/2.png)
Black-throated Blue Warbler
you sure you didn't cache that error? haha
comment out this part too for now
if (cachedResponse) {
return new Response(JSON.stringify(cachedResponse), { status: 200 });
}
![Avatar](https://cdn.discordapp.com/embed/avatars/5.png)
Red imported fire antOP
haha, it was nt' cache does save, I just commented out and still same. but i am suspecting returning response has some issue because success log printed and then error raised
Set cache success { data: { componentHomePageContent: { data: [Object] } } }
āØÆ Error: GraphQL Error (Code: 200): {"response":{"error":"[object Object]","status":200,"headers":
{}},"request":{"query":"query getHomePageContent {\n componentHomePageContent {\n data {\n
attributes {\n seo {\n title\n meta_robots\n meta_discription\n
link_canonical\n }\n Mission_block {\n
![Avatar](https://cdn.discordapp.com/embed/avatars/2.png)
Black-throated Blue Warbler
what does it look like when you console log data
from:
const data = await response.json();
const data = await response.json();
![Avatar](https://cdn.discordapp.com/embed/avatars/5.png)
Red imported fire antOP
and when i log the data
{ data: { componentHomePageContent: { data: [Object] } } }
![Avatar](https://cdn.discordapp.com/embed/avatars/2.png)
Black-throated Blue Warbler
hmm well that looks valid, and i don't see an errors key
try just returning data
![Avatar](https://cdn.discordapp.com/embed/avatars/5.png)
Red imported fire antOP
Error: Cannot read properties of undefined (reading 'forEach')
And my page not even have any forEach š
And my page not even have any forEach š
![Avatar](https://cdn.discordapp.com/embed/avatars/2.png)
Black-throated Blue Warbler
I stopped using graphql for simple projects a while back, it just creates too much complexity. Is there a good reason for you to be using graphql on this site? just curious
![Avatar](https://cdn.discordapp.com/embed/avatars/5.png)
Red imported fire antOP
Backend only provides graphql
![Avatar](https://cdn.discordapp.com/embed/avatars/2.png)
Black-throated Blue Warbler
i'd say thats a pretty solid reason then, i think you'll have to do some digging on how to setup graphql-tag with the latest next.js cacheing. Unfortuantely i'm not very experienced with it.
When I was using graphql on my projects I just wrote my own fetch wrapper and didn't use any libraries
When I was using graphql on my projects I just wrote my own fetch wrapper and didn't use any libraries
![Avatar](https://cdn.discordapp.com/embed/avatars/5.png)
Red imported fire antOP
OK thank you any way
![Avatar](https://cdn.discordapp.com/embed/avatars/2.png)
Black-throated Blue Warbler
example of what i mean by using graphql without library (with next.js custom fetch)
const { data } = await fetch(process.env.GRAPHQL_API_URL, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
query: `
query getPosts {
posts {
edges {
node {
title
excerpt
slug
date
}
}
}
}
`,
}),
next: { revalidate: 10 },
}).then((res) => res.json());
could slap a query in there just to see if it works with the revalidate like it should