How revalidateTag actually works?
Answered
ZgazenaMacka posted this in #help-forum
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.
The fetch API request looks like this and it's inside /app/api/latestPost
Now I don't get where exactly I'm calling revalidateTag('testTag').
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_cache17 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
Whatever I tried I did not see the wanted result both on vercel deployed app or on local build.
Thank you very much.
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
2. you could use
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 function2. 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.@ZgazenaMacka **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.
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_cacheAnswer
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?
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
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
@ZgazenaMacka 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
or add a console.log in your database operation function