skip to Main Content

I have an odd issue I am dealing with. I have this useEffect function which is supposed to run on my program’s start to check that they are logged in, and generate a dynamic element, named lists. Code is below:

// Initial Effect: Fetch access and lists data on component mount
useEffect(() => {
    console.log('Running on launch!')
    getAccess();
    getLists();
}, []);

I am expecting this to run getLists() everytime the page is loaded. This is because our users can interact with the lists — they can add items to it and delete items (which updates our Postgres backend). I always want to dynamically pull the latest version of lists.

The function and route are shown below.

// Fetch list data from the server
const getLists = async () => {
    const data = await fetch("/api/prospects/getLists/");
    const json_data = await data.json();
    console.log(json_data);
    setLists([...json_data]);
};
"use server";

import * as db from "../../../../lib/db"
import { NextRequest, NextResponse } from 'next/server';

export async function GET(req: NextRequest) {
    const list = await db.query(`
    SELECT id, name FROM "List"
    ORDER BY name ASC
    `, []);
    
    return NextResponse.json(list.rows);
}

However, let’s say I add an element to the list and then refresh my page. I can verify the useEffect function is being called as I see "Running on launch!" executed in my console. However, the console.log where we log the json_data will ALWAYS show the original state of the list table. If I start the program with 5 elements in list, and add a sixth, no matter how many times I refresh the page, it is showing me that my route is only returning the original 5 elements. Same issue with deletion. It never gets updated.

Importantly, I confirmed that my postgres table is indeed taking the changes in real time. So it isn’t an issue with adding or deletion.

How do I fix it so it dynamically always pulls the latest version of the List table on refresh?

It should also be important to note it works correctly in my development environment, but if I build it using npm run build on my local machine, or push it to github to my live version on vercel, then this issue happens.

I also confirmed that if I hit the API route directly in my browser: http://localhost:3000/api/prospects/getLists, that it doesn’t show the updated list either.

3

Answers


  1. Next.js refreshes the API routes every time a request is made. You have to disable caching in you api route. You can do something like this.

    "use server"
    import * as db from "../../../../lib/db"
    import { NextRequest, NextResponse } from 'next/server';
    
    export async function GET(req: NextRequest) {
        cons list = await db.query(`
        SELECT id, name FROM "List"
        ORDER BY name ASC
        `, []);
        
        const response = NextResponse.json(list.rows);
    
        // Disable caching
        response.headers.set('Cache-Control', 'no-store, no-cache, must-revalidate, proxy-revalidate');
        response.headers.set('Pragma', 'no-cache');
        response.headers.set('Expires', '0');
    
        return response;
    }
    

    Then console log to check it is still caching.

    const getLists = async () => {
        const data = await fetch("/api/prospects/getLists/", {
            cache: 'no-store'
        });
        const json_data = await data.json();
        console.log(json_data);
        setLists([...json_data]);
    };
    

    Otherwise, if you don’t like that approach, you can try dynamic updating with getServerSideProps or maybe re-fetch the data on the client side with intervals. All in all, this should work for this purpose.

    Login or Signup to reply.
  2. It looks like you’re having a caching issue, especially given that the problem occurs only in the production environment. Here’s a solution to ensure that the getLists function always fetches the most recent data.

    Disable Caching for the API Route

    To prevent caching of the API response, you can explicitly set the cache headers in your API route. Modify your GET handler to include the appropriate headers:

    import * as db from "../../../../lib/db"
    import { NextRequest, NextResponse } from 'next/server';
    
    export async function GET(req: NextRequest) {
        const list = await db.query(`
            SELECT id, name FROM "List"
            ORDER BY name ASC
        `, []);
        
        const response = NextResponse.json(list.rows);
        
        // Set cache control headers to disable caching
        response.headers.set('Cache-Control', 'no-store');
        
        return response;
    }
    
    Login or Signup to reply.
  3. You need to disable caching if you are having a complete dynamic page where things change quite often. Or you might want to add a re validate time to the page.

    export const re validate = 60
    

    So, basically the above code will re validate the cache in 60 seconds. You can set it as per your requirement.

    The above line code should be in a page directly exported. You can have look in the below code for more context.

    import Layout from "@/components/layout";
    import Container from "@/components/ui/Container";
    import PostCard from "@/components/ui/PostCard";
    import { getPages } from "@/utils/notion";
    import type { Metadata } from "next";
    
    export const metadata: Metadata = {
      title: "Recent Updates",
      description: "Find all the latest articles and blogs in this page."
    }
    
    export const revalidate = 60
    
    export default async function Home() {
      const response = await getPages();
      const pages = (response.results)
    
      return (
        <Container>
          <Layout>
            <div className="md:mt-20 mt-10">
              {pages.map((post: any) => (
                <PostCard key={post.id} post={post} />
              ))}
            </div>
          </Layout>
        </Container>
      );
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search