Next.js Discord

Discord Forum

Dynamic content on static page (ISR) - app router

Unanswered
Basset Bleu de Gascogne posted this in #help-forum
Open in Discord
Avatar
Basset Bleu de GascogneOP
Hi, I would like my pages to be static but the footer be dynamic since it has list of all of my blogs. I haven't been able to get this working. The correct term for this seems to be ISR. I found only instructions with Page router: https://nextjs.org/docs/pages/building-your-application/data-fetching/incremental-static-regeneration. I am using Directus CMS for calls to backend, not fetch.

I found out that it works when in root layout you put this line export const revalidate = 60; but it makes all my pages dynamic.

Am I thinking this wrong?

6 Replies

Avatar
Basset Bleu de GascogneOP
Sure, here's my root layout layout.tsx:

export const revalidate = 60; // to do fix?
import type { Metadata } from "next";
import { Inter } from "next/font/google";
import React, { Suspense } from "react";
import "./globals.css";
import { ThemeProvider } from "@/components/ThemeProvider";
import { NavBar } from "@/components/NavBar";
import Loading from "./loading";
import { Footer } from "@/components/Footer/Footer";

const inter = Inter({ subsets: ["latin"] });

export default function RootLayout({
    children
}: Readonly<{
    children: React.ReactNode;
}>) {
    return (
        <html lang="en" suppressHydrationWarning>
            <body className={inter.className}>
                <ThemeProvider
                    attribute="class"
                    defaultTheme="system"
                    enableSystem
                    disableTransitionOnChange
                >
                    <Suspense fallback={<Loading />}>
                        <div className="px-5 max-w-6xl mx-auto">
                            <NavBar />
                            {children}
                            <Footer />
                        </div>
                    </Suspense>
                </ThemeProvider>
            </body>
        </html>
    );
}
My footer.tsx is just styles and basic footer stuff. But there's FeaturedBlogs in the footer, which is this:

import { getFeaturedBlogs } from "@/services/BlogRequests";
import Link from "next/link";

export default async function FeaturedBlogs() {
    const blogs = await getFeaturedBlogs();
    return (
        <div>
            <h6 className="mb-4 text-sm font-semibold uppercase text-gray-900 dark:text-white">
                Featured blogs
            </h6>
            <ul className="space-y-3">
                {blogs.length === 0 && (
                    <li className="text-gray-500 dark:text-gray-400">No featured blogs</li>
                )}
                {blogs.map((blog) => (
                    <li key={blog.id}>
                        <Link
                            href={`/blog/${blog.id}`}
                            className="text-gray-500 hover:text-gray-900 dark:text-gray-400 dark:hover:text-white"
                        >
                            {blog.title}
                        </Link>
                    </li>
                ))}
            </ul>
        </div>
    );
}
And my CMS call:

import { createDirectus, rest, readItem, authentication, readUser, readItems } from "@directus/sdk";
import { Blog, User } from "@/types
";

// create a Directus client to connect to the Directus API
const client = createDirectus(process.env.DIRECTUS_URL as string)
    .with(rest({ onRequest: (options) => ({ ...options, cache: "no-cache" }) }))
    .with(authentication());


// other calls


export const getFeaturedBlogs = async () => {
    try {
        await client.setToken(process.env.DIRECTUS_KEY as string);
        const res = (await client.request(readItems("blog"))) as Blog[];
        // Filter and sort the blogs. Return only the first 3 featured blogs
        const featuredBlogs = res
            .filter((blog) => blog.published)
            .filter((blog) => blog.tags?.includes("featured"))
            .sort((a, b) => new Date(b.date_created).getTime() - new Date(a.date_created).getTime())
            .slice(0, 3);
        return featuredBlogs;
    } catch (error) {
        console.error("Error while fetching featured blogs", error);
        return [];
    }
};


Build logs:
Image
My whole source code is here if you are interested or reading in GitHub is easier for you: https://github.com/kristianka/kristiankahkonen.com
Avatar
Basset Bleu de GascogneOP
Bump
Avatar
Basset Bleu de GascogneOP
Solved by making the page SSG and revalidating via revalidatePath by webhook from Directus