Next.js Discord

Discord Forum

How revalidateTag actually works?

Answered
ZgazenaMacka posted this in #help-forum
Open in Discord
Hello. I'm trying to cache "latest post" on my homepage and once the new post is posted to revalidate cache for fetching "latest post" but I can't get it to work. Can someone tell me the workflow and how to achieve the wanted behaviour.

Component that fetches latest post and then displays the data. Here I defined a tag for the fetch. The component is in the /app/page.js which is the homepage.
import styles from '@/components/latest/latest.module.scss';
import { formatMongoDate } from '@/lib/utils';
import Link from 'next/link';
import { StandardBtn } from '../buttons/standardBtn/StandardBtn';
import Image from 'next/image';

const getData = async () => {
    const res = await fetch(`${process.env.DOMAIN_URL}/api/latestPost`, { next: { tags: 'testTag' } });
    if (!res.ok) {
        throw new Error('Failed to fetch LatestQuad data');
    }
    return res.json();
}

export const LatestPregled = async () => {
    const data = await getData();

    return (
        ..// DISPLAYING FETCHED DATA ABOUT LATEST POST
    )
}


The fetch API request looks like this and it's inside /app/api/latestPost
import { dbConnect } from "@/lib/mongo/dbConnect"
import reviewModel from "@/lib/mongo/models/reviewModel"
import { NextResponse } from "next/server"

export const GET = async (request) => {
    try {
        dbConnect()
        const data = await reviewModel.find({ 'movies': { $size: 4 } }).sort({ createdAt: -1 }).limit(1)
        console.log('Latest quad post successfully fetched', data[0].reviewTitle)
        return NextResponse.json(data)
    } catch (err) {
        throw new Error('Failed to fetch latest quad post', err)
    }
}


Now I don't get where exactly I'm calling revalidateTag('testTag').
Answered by Ray
for you case, I think its better to use revalidatePath with server action because it will update the ui accordingly and you don't need to wrap your query with unstable_cache
View full answer

17 Replies

Inside the function that handles new post form? That function is within the client component which contains the new post form and once form is submitted I do a fetch of API request that creates a new post in database. Here's fetch from new post form function.

const response = await fetch(`${process.env.NEXT_PUBLIC_DOMAIN_URL}/api/reviews`, {
                    method: 'POST',
                    body: JSON.stringify(review),
                    headers: {
                        'Content-Type': 'application/json',
                    },
                });
Also here's function behind that API request, located in /app/api/reviews as POST request
export async function POST(request) {
    dbConnect()
    const data = await request.json()
    const { reviewTitle, movies, comments, likes, contentImages, selectedcategory, quadOgImage, quadOgImagePath } = data
    console.log(movies)
    console.log('links: ', [quadOgImage, quadOgImagePath])

    let slug = ''

    // checking if all required fields are filled

    // adding document to db
    try {
        let review = {}
        if (movies.length === 1) {
            review = await reviewModel.create({
                reviewTitle,
                slug: slug,
                movies,
                comments,
                likes,
                contentImages,
                reviewType: 'single',
                category: selectedcategory,
            })
        }
        if (movies.length === 4) {
            review = await reviewModel.create({
                reviewTitle,
                slug: slug,
                movies,
                comments,
                likes,
                contentImages,
                reviewType: 'quad',
                category: selectedcategory,
                quadOgImage: quadOgImage,
                quadOgImagePath: quadOgImagePath,
            })
        }
        return new NextResponse(JSON.stringify(review), {
            status: 200
        })
    } catch (error) {
        return new NextResponse(JSON.stringify({ error: error.message }), {
            status: 400
        })
    }
}


Whatever I tried I did not see the wanted result both on vercel deployed app or on local build.

Thank you very much.
@ZgazenaMacka Hello. I'm trying to cache "latest post" on my homepage and once the new post is posted to revalidate cache for fetching "latest post" but I can't get it to work. Can someone tell me the workflow and how to achieve the wanted behaviour. **Component that fetches latest post and then displays the data. Here I defined a tag for the fetch. The component is in the /app/page.js which is the homepage.** import styles from '@/components/latest/latest.module.scss'; import { formatMongoDate } from '@/lib/utils'; import Link from 'next/link'; import { StandardBtn } from '../buttons/standardBtn/StandardBtn'; import Image from 'next/image'; const getData = async () => { const res = await fetch(`${process.env.DOMAIN_URL}/api/latestPost`, { next: { tags: 'testTag' } }); if (!res.ok) { throw new Error('Failed to fetch LatestQuad data'); } return res.json(); } export const LatestPregled = async () => { const data = await getData(); return ( ..// DISPLAYING FETCHED DATA ABOUT LATEST POST ) } **The fetch API request looks like this and it's inside /app/api/latestPost** import { dbConnect } from "@/lib/mongo/dbConnect" import reviewModel from "@/lib/mongo/models/reviewModel" import { NextResponse } from "next/server" export const GET = async (request) => { try { dbConnect() const data = await reviewModel.find({ 'movies': { $size: 4 } }).sort({ createdAt: -1 }).limit(1) console.log('Latest quad post successfully fetched', data[0].reviewTitle) return NextResponse.json(data) } catch (err) { throw new Error('Failed to fetch latest quad post', err) } } Now I don't get where exactly I'm calling revalidateTag('testTag').
1. the GET endpoint is static by default. You should make it dynamic by doing export const dynamic = 'force-dynamic' but It is better to move the database operation to the getData function instead but you will need to use unstable_cache for tagging the function

2. you could use revalidateTag in the POST endpoint after inserting the data and the new data should show on the next visit of the route.
Answer
If I understood right.
I should create a server action (a new standalone file that will export a function marked with "use server"), that function should call revalidatePath instead of revalidateTag?
Do I then trigger that server action in the client component function that handles sending a form through API request or inside POST request?
Also path for revalidatePath should be the GET request path mentioned in the latestPost component?
@ZgazenaMacka If I understood right. I should create a server action (a new standalone file that will export a function marked with "use server"), that function should call revalidatePath instead of revalidateTag? Do I then trigger that server action in the client component function that handles sending a form through API request or inside POST request?
I should create a server action (a new standalone file that will export a function marked with "use server"), that function should call revalidatePath instead of revalidateTag?
yes
Do I then trigger that server action in the client component function that handles sending a form through API request or inside POST request?
yes, <form action={serverAction />

Also path for revalidatePath should be the GET request path mentioned in the latestPost component?
should be the pathname for that page. eg: revalidatePath("/latest-pregled")
As for the form, I am currently using onSubmit, the whole page where the form is client
and you no longer need the GET and POST endpoint
@ZgazenaMacka As for the form, I am currently using onSubmit, the whole page where the form is client
you can use server action in client component
onSubmit={async (e) => {
  e.preventDefault()
  const {errors} = await serverAction(new FormData(e.currentTarget))
  if (errors) {
    // handle error
  }
}}
Alright, thanks. Will try it now
@Ray How can I check if my fetch was from database or cache is served?
I think I got it working now but want to check to be 100% sure
@ZgazenaMacka <@743561772069421169> How can I check if my fetch was from database or cache is served? I think I got it working now but want to check to be 100% sure
you could enable the fetching log in the next.config
const nextConfig = {
  logging: {
    fetches: { fullUrl: true },
  }
}
Added that to the config and now I see it. One thing confuses me, I always see HIT, with revalidated path or even without revalidation, it is always HIT. Only if I hard reload then I get SKIP due to hard reload
the data gets updated tho
I guess it's because of client side router caching