Search code examples
cachingnext.jsserver-side-renderingnext.js13

Next 13 page not dynamic


Hi here is one of my pages in next 13 in the app directory :

import { cookies } from "next/headers";
import Link from "next/link";
import styles from "@/styles/chatPage/ChatPage.module.css";
import ChatClient from "@/components/chatPage/ChatClient";
import Profile_Service from "@/services/Profile.service";
import { Refresher } from "@/components/refresher/Refresher";

export default async function ChatPage() {
    let     token: string | undefined;
    let     myself: User;

    try {
        token = cookies().get("crunchy-token")?.value;
        if (!token)
            throw new Error("No token value");

        const profilService = new Profile_Service(token);
        myself = await profilService.getProfileAndAvatar();

    } catch (err) {
        console.log(err);
        return (
            <div className={styles.error}>
                <h2>Oops... Something went wrong!</h2>
                <Link href={"/home"} className={styles.errorLink}>
                    <p>Return to Home Page!</p>
                </Link>
            </div>
        )
    }

    return (
        <>
            <Refresher />
            <ChatClient token={token} myself={myself}/>
        </>
    )
}

My problem is that this server component is only called the first time I go to the page and i had to add this Refresher component in order to call the try catch function every time i go to this page :

// Sample Refresher Component
// to be imported into SSR page
// needing a refresh after 
// next.js appDir Link nav
//

'use client'
import { useRouter } from 'next/navigation'
import { useEffect } from 'react'

export function Refresher() {
    const router = useRouter()

    useEffect(() => {
        router.refresh()
    }, [router])

    return <></>
}

I don't know what to do, isn't it possible to tell next to call this function every time I go to this page ? In the next documentation the call to the cookies() function should tell next that this page is dynamyc, but even like this it is called just once. My problem here is that I fetch the client data here, but if i change some data when i come back to this page it doesnt fetch it again. I tried the "export dynamic='force-dynamic" the revalidate=0 the fetch=no-store a,nd evrything that I can find in the documentation but i can't find any working solution. Currently I found this Refresher component solution in a forum where people had the same problem as me, but it is not a very good solution and i'd like to not use it if i can... Can someone help me ??

I tried all constant exports in the next documentation but its the same, besides for my middelxare its excatly the same, it is called juste the first time i go to a page, but not again when i go back to it...

First edit: I think i just don't understand how server components should work... I tried again a little test with two pages "/welcome" and "/login". My final purpose would be to access the cookies when i go to this page so that the server side is triggered every time i go to the page. Here is my Welcome Page :

import ServerComponent from "@/components/ServerComponent";
import Link from "next/link";
import { Suspense } from "react";

// export const dynamic = 'auto'
// export const revalidate = 0

export default async function Welcome() {

  console.log("laaaaa welcome");

  return (
    <main>
      <p>Crunchy Pong !</p>
      <Suspense fallback={<>Loading...</>}>
        <ServerComponent/>
      </Suspense>
      <Link href="/welcome/login">Login</Link>
    </main>
  );
}

and here is my login Page :


import ServerComponent from "@/components/ServerComponent";
import Link from "next/link";
import { Suspense } from "react";

// export const dynamic = 'auto'
// export const revalidate = 0

export default function SignUpPage() {

  console.log("laaaa login");
  
  return (
    <>
      <p>Login Pong !</p>
      <Suspense fallback={<>Loading...</>}>
        <ServerComponent/>
      </Suspense>
      <Link href="/welcome">Welcome</Link>
    </>
  );
}

It's just a little example that does nothing, they both use this server Component :

export default async function ServerComponent() {
    let data: any = 'nothing';
    try {
        const res = await fetch('https://jsonplaceholder.typicode.com/todos/1');
    
        data = await res.json();
        console.log(data);
    }
    catch (error) {
    
    }
    return (
        <>
        {data.title}
        </>
    )
}

So without the "export const revalidate = 0" I can see this : GET https://jsonplaceholder.typicode.com/todos/1 200 in 2ms (cache: HIT) and with hit I can see the cache is MISS ; but i do not understand why the console.log in the pages and this server component are executed just the first time I go to the page.Is it the same for all server components ? Isn't it triggered every time we go to the page ? I expected it because i want to use some httpOnly cookies and I was thinking it would check the cookies every time i would go to a page... Thanks for your help !


Solution

  • The Next 13 docs are wrong, or at least VERY misleading.

    When it comes to the Router Cache, you cannot configure a Page to be dynamic or not. Declarations like export const dynamic = 'force-dynamic' or export const dynamic = 'auto' are not respected for Pages. Likewise, the cache options for your fetch requests do not matter.

    Source: https://github.com/vercel/next.js/discussions/54075

    The only ways to affect the Router Cache are to use Server Actions OR to use router.refresh().