#nextjs #cache #revalidation #isr

Day 17 β€” Revalidating Data: Freshness on Demand

🧭 Day 17 β€” Revalidating Data: Freshness on Demand

Zero to Hero β€” Hands-on Next.js Tutorial

Next.js is aggressive about caching. If you fetch data in a Server Component, Next.js might cache it indefinitely. When you perform a Server Action (e.g., adding a new To-Do item), the UI won’t update unless you tell Next.js: β€œThe data has changed!”


🟦 1. revalidatePath

This is the most common way to refresh data. It purges the cache for a specific URL path.

'use server';

import { revalidatePath } from 'next/cache';

export async function createTodo(formData: FormData) {
  await db.todo.create({ ... });
  
  // "Hey Next.js, throw away the cached HTML for /todos"
  // "The next time someone visits, regenerate it."
  revalidatePath('/todos');
}
  • revalidatePath('/todos') -> Refreshes only that page.
  • revalidatePath('/', 'layout') -> Refreshes the root and everything inside it.

🟩 2. revalidateTag

Path-based revalidation is simple, but what if the same data (e.g., a list of products) is used on the Home Page, the Shop Page, AND the Admin Dashboard? You’d have to call revalidatePath 3 times. 😫

Better: Use Cache Tags.

  1. Tag the fetch:

    // getProducts.ts
    fetch('https://api/products', { next: { tags: ['products'] } });
  2. Invalidate the tag:

    // updateProduct.ts ('use server')
    import { revalidateTag } from 'next/cache';
    
    export async function updateProduct() {
      await db.update(...)
      
      // Purge EVERY fetch request marked with 'products'
      // No matter which page it is on!
      revalidateTag('products'); 
    }

🟧 3. Optimistic Updates (useOptimistic)

Revalidation takes time (Server Roundtrip). To make the UI feel instant, use useOptimistic.

'use client';
import { useOptimistic } from 'react';

export function TodoList({ todos }) {
  const [optimisticTodos, addOptimisticTodo] = useOptimistic(
    todos,
    (state, newTodo) => [...state, newTodo]
  );

  return (
    <div>
       {optimisticTodos.map(t => <div key={t.id}>{t.title}</div>)}
       
       <form action={async (formData) => {
         const title = formData.get('title');
         // 1. Show the new item IMMEDIATELY (Mock ID)
         addOptimisticTodo({ id: Math.random(), title });
         
         // 2. Actually save to server (Background)
         await createTodo(formData);
       }}>
         <button>Add</button>
       </form>
    </div>
  );
}

πŸ§ͺ Challenge: Day 17

  1. Create a list of items fetched with a tag: fetch('...', { next: { tags: ['items'] } }).
  2. Create a button β€œAdd Random Item”.
  3. In the Server Action, add the item and call revalidateTag('items').
  4. Observe closely: The page should automatically reload the list without a full browser refresh!

See you tomorrow for Cookies & Headers! πŸͺ