3

I have a feed component in my application that fetches data from an API endpoint. The component works fine when I test it on my local build, but when I deploy it on Vercel, it doesn't fetch the latest data. I suspect this issue is related to caching. To address the problem, I added the cache: 'no-store' option to the fetch request, but it doesn't seem to solve the problem. I would appreciate any help or suggestions to resolve this issue.

"use client";

  const fetchPosts = async () => {
    const response = await fetch("/api/prompt", {
      cache: 'no-store',
    });
    const data = await response.json();
    setAllPosts(data);
  };

  useEffect(() => {
    fetchPosts();
  }, []);

GitHub Link: https://github.com/justinwkUKM/promptify/blob/main/components/Feed.jsx

Note: Please provide any suggestions or solutions for the caching issue when deploying on Vercel. Thank you!

3 Answers3

1

You have literally the exact same issue as me. I was able to find a fix with this:

/app/api/prompt/route.js

import Prompt from "@models/prompt";
import { connectToDB } from "@utils/database";

export const revalidate = 1; //revalidate api every 1 second
export const GET = async (request) => {
    try {
        await connectToDB()

        const prompts = await Prompt.find({}).populate('creator')

        return new Response(JSON.stringify(prompts), { status: 200 })
    } catch (error) {
        return new Response("Failed to fetch all prompts", { status: 500 })
    }
} 

I can't really explain why Next works this way, but this fixed it for me.

vunsh
  • 25
  • 3
  • It works to me, thanks. In my case, my api route became static (not ssg), so that's why data were not updated. I have used revalidate = 0 without double refreshing the browser. – Sergo Jul 01 '23 at 21:32
  • Thank you so much! I deployed my interview task and saw this. This might just help me clear it! – Divyesh Parmar Jul 28 '23 at 20:36
1

For anyone who is still encountering this issue when deploying to Vercel:

The issue is being caused by the file being rendered statically by Next.JS. According to the documentation: By default, Next.js statically renders routes to improve performance.

You can see this in the output printed when npm run build is executed. A simple example of the output is shown below.

Route (app)
┌ ○ /api/prompt
└ λ /api/prompt/[id]

λ  (Server)  server-side renders at runtime (uses getInitialProps or getServerSideProps)
○  (Static)  automatically rendered as static HTML (uses no initial props)

In order to prevent Next.JS from statically rendering this site it needs some way to know its dynamic. According to the documentation: if a dynamic function or a dynamic fetch() request (no caching) is discovered, Next.js will switch to dynamically rendering the whole route at request time.

The static and dynamic behavior of a route can be controlled using the Route Segment Config features of Next.JS

Specifically you can export the dynamic variable with the value of 'force-dynamic' as shown

import Prompt from "@models/prompt";
import { connectToDB } from "@utils/database";

export const dynamic = 'force-dynamic';
export const GET = async (request) => {
  try {
    await connectToDB();

    const prompts = await Prompt.find({}).populate('creator');

    return new Response(JSON.stringify(prompts), { status: 200 });
  } catch (error) {
    return new Response("Failed to fetch all prompts", { status: 500 });
  }
} 

This export ensures that Next.JS renders the route dynamically!

A little side note: This is functionally similar to adding export const revalidate = 0; according to the docs.

0

I encountered a similar issue when deploying my app on Vercel. However, I was able to resolve it by updating the fetchPosts function to include the following changes:

const response = await fetch("/api/prompt", { next: { revalidate: 1 } });

Additionally, I made updates to the app/api/prompt/route.js file

import Prompt from "@models/prompt";
import { connectToDatabase } from "@utils/database";
import { NextRequest, NextResponse } from "next/server";
import { revalidatePath } from "next/cache";

export const GET = async (request) => {
  try {
    await connectToDatabase();

    const prompts = await Prompt.find({}).populate("creator");

    //To dynamically get the path
    const path = request.nextUrl.searchParams.get("path") || "/";

    revalidatePath(path);

    return NextResponse.json(prompts);
  } catch (error) {
    return new Response("Failed to fetch all prompts", { status: 500 });
  }
};

For a detailed explanation, you can refer to this YouTube video: https://www.youtube.com/watch?v=TZXMT-EG7Ak&t=98s

I hope that this helps you in resolving the issue.