Skip to content

Commit db1408a

Browse files
authored
Added new examples (#161)
* Extra examples * Layout changes * Added unstable cache example
1 parent 31eb08f commit db1408a

File tree

13 files changed

+1235
-76
lines changed

13 files changed

+1235
-76
lines changed

examples/redis-minimal/README.md

Lines changed: 97 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,56 @@ The application includes several examples demonstrating different Next.js cachin
4141

4242
Overview page listing all available examples with descriptions and features.
4343

44-
### 2. Fetch with Tags (`/examples/fetch-tags`)
44+
### 2. Default Cache (`/examples/default-cache`)
45+
46+
Demonstrates the default fetch caching behavior with `force-cache`.
47+
48+
**Features:**
49+
50+
- Default caching behavior (indefinite cache duration)
51+
- Perfect for static or rarely-changing data
52+
- Shows how Next.js caches by default
53+
54+
**Try it:**
55+
56+
- Visit `/examples/default-cache` to see cached data
57+
- The timestamp will remain the same on subsequent requests
58+
- Data is cached until manually cleared or build is redeployed
59+
60+
### 3. No Store (`/examples/no-store`)
61+
62+
Shows fetch with `no-store` option, which always fetches fresh data.
63+
64+
**Features:**
65+
66+
- Never caches responses
67+
- Always fetches fresh data from API
68+
- Perfect for real-time or user-specific data
69+
- Timestamp changes on every request
70+
71+
**Try it:**
72+
73+
- Visit `/examples/no-store` to see fresh data on every load
74+
- Refresh the page multiple times - timestamp changes each time
75+
- Compare with other caching strategies
76+
77+
### 4. Time-based Revalidation (`/examples/time-based-revalidation`)
78+
79+
Shows fetch with time-based revalidation (standalone, without tags).
80+
81+
**Features:**
82+
83+
- Automatic revalidation after specified time (30 seconds)
84+
- Balances freshness with performance
85+
- Standalone example of `next.revalidate`
86+
87+
**Try it:**
88+
89+
- Visit `/examples/time-based-revalidation` to see cached data
90+
- Refresh within 30 seconds - timestamp stays the same
91+
- Wait 30+ seconds and refresh - timestamp updates
92+
93+
### 5. Fetch with Tags (`/examples/fetch-tags`)
4594

4695
Demonstrates fetch caching with tags and time-based revalidation.
4796

@@ -59,7 +108,26 @@ Demonstrates fetch caching with tags and time-based revalidation.
59108
- Click "Clear Cache" to invalidate the cache
60109
- Reload the page to see fresh data
61110

62-
### 3. ISR with Static Params (`/examples/isr/blog/[id]`)
111+
### 6. unstable_cache (`/examples/unstable-cache`)
112+
113+
Demonstrates persistent caching with `unstable_cache` for function results.
114+
115+
**Features:**
116+
117+
- Cache any function, not just fetch requests
118+
- Tags and revalidation support
119+
- Side-by-side comparison with fetch caching
120+
- Perfect for database queries and computations
121+
- Shows when to use unstable_cache vs fetch
122+
123+
**Try it:**
124+
125+
- Visit `/examples/unstable-cache` to see both caching methods
126+
- Compare the timestamps and behavior
127+
- Click "Clear Tag Cache" to invalidate both caches
128+
- Understand when to use unstable_cache vs fetch
129+
130+
### 7. ISR with Static Params (`/examples/isr/blog/[id]`)
63131

64132
Incremental Static Regeneration with `generateStaticParams`.
65133

@@ -76,7 +144,7 @@ Incremental Static Regeneration with `generateStaticParams`.
76144
- Try different IDs like `/examples/isr/blog/2`, `/examples/isr/blog/3`
77145
- Check the rendered timestamp to see caching in action
78146

79-
### 5. Static Params Test (`/examples/static-params/[testName]`)
147+
### 8. Static Params Test (`/examples/static-params/[testName]`)
80148

81149
Tests static params generation with dynamic routes.
82150

@@ -94,19 +162,39 @@ Tests static params generation with dynamic routes.
94162

95163
## API Routes
96164

97-
### Clear Cache (`/api/cache`)
165+
### Cache Revalidation (`/api/revalidate`)
98166

99-
Clears cache for a specific tag.
167+
Unified endpoint for revalidating cache by tag or path.
100168

101169
**Usage:**
102170

103-
- `GET /api/cache?tag=futurama` - Clears cache for the "futurama" tag
104-
- Default tag is "futurama" if not specified
171+
**Tag-based revalidation (GET):**
172+
173+
- `GET /api/revalidate?tag=futurama` - Revalidates cache for the "futurama" tag
174+
175+
**Tag-based revalidation (POST):**
176+
177+
- `POST /api/revalidate` with body `{ "tag": "futurama" }` - Revalidates cache for a tag
178+
179+
**Path-based revalidation (POST):**
180+
181+
- `POST /api/revalidate` with body `{ "path": "/examples/default-cache" }` - Revalidates cache for a specific path
105182

106-
**Example:**
183+
**Examples:**
107184

108185
```bash
109-
curl http://localhost:3000/api/cache?tag=futurama
186+
# Revalidate by tag (GET)
187+
curl http://localhost:3000/api/revalidate?tag=futurama
188+
189+
# Revalidate by tag (POST)
190+
curl -X POST http://localhost:3000/api/revalidate \
191+
-H "Content-Type: application/json" \
192+
-d '{"tag": "futurama"}'
193+
194+
# Revalidate by path (POST)
195+
curl -X POST http://localhost:3000/api/revalidate \
196+
-H "Content-Type: application/json" \
197+
-d '{"path": "/examples/default-cache"}'
110198
```
111199

112200
## Cache Handler

examples/redis-minimal/src/app/api/cache/route.ts

Lines changed: 0 additions & 18 deletions
This file was deleted.
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { revalidateTag, revalidatePath } from "next/cache";
2+
import { NextRequest } from "next/server";
3+
4+
export async function GET(request: NextRequest) {
5+
const searchParams = request.nextUrl.searchParams;
6+
const tag = searchParams.get("tag");
7+
8+
if (tag) {
9+
try {
10+
revalidateTag(tag, "max");
11+
return new Response(`Cache cleared for tag: ${tag}`, {
12+
status: 200,
13+
});
14+
} catch (error) {
15+
return new Response(`Error clearing cache for tag: ${tag}`, {
16+
status: 500,
17+
});
18+
}
19+
}
20+
21+
return new Response("Tag parameter is required for GET requests", {
22+
status: 400,
23+
});
24+
}
25+
26+
export async function POST(request: NextRequest) {
27+
try {
28+
const body = await request.json();
29+
const { tag, path } = body;
30+
31+
if (tag) {
32+
revalidateTag(tag, "max");
33+
return new Response(`Cache cleared for tag: ${tag}`, {
34+
status: 200,
35+
});
36+
}
37+
38+
if (path) {
39+
const type = body.type as "page" | "layout" | undefined;
40+
if (type) {
41+
revalidatePath(path, type);
42+
return new Response(`Cache revalidated for ${type}: ${path}`, {
43+
status: 200,
44+
});
45+
}
46+
revalidatePath(path);
47+
return new Response(`Cache revalidated for path: ${path}`, {
48+
status: 200,
49+
});
50+
}
51+
52+
return new Response("Either 'tag' or 'path' is required", {
53+
status: 400,
54+
});
55+
} catch (error) {
56+
return new Response(`Error revalidating cache: ${error}`, {
57+
status: 500,
58+
});
59+
}
60+
}
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
import { ExampleLayout } from "@/components/ExampleLayout";
2+
import { InfoCard } from "@/components/InfoCard";
3+
import { CodeBlock } from "@/components/CodeBlock";
4+
import { RevalidatePathButton } from "@/components/RevalidatePathButton";
5+
import { FuturamaCharacter } from "@/types/futurama";
6+
7+
export default async function DefaultCacheExample() {
8+
let name: string;
9+
let character: FuturamaCharacter;
10+
const timestamp = new Date().toISOString();
11+
12+
try {
13+
const characterResponse = await fetch(
14+
"https://api.sampleapis.com/futurama/characters/2",
15+
{
16+
cache: "force-cache",
17+
}
18+
);
19+
character = await characterResponse.json();
20+
name = character.name.first;
21+
} catch (error) {
22+
console.error("Error fetching character data:", error);
23+
return (
24+
<ExampleLayout
25+
title="Default Caching Example"
26+
description="Demonstrates default fetch caching behavior with force-cache"
27+
>
28+
<div className="text-red-600 dark:text-red-400">
29+
An error occurred during fetch. Please check your network connection.
30+
</div>
31+
</ExampleLayout>
32+
);
33+
}
34+
35+
return (
36+
<ExampleLayout
37+
title="Default Caching (force-cache) Example"
38+
description="This example demonstrates the default fetch caching behavior. When no cache options are specified, Next.js uses 'force-cache' which caches data indefinitely until manually invalidated."
39+
actions={<RevalidatePathButton path="/examples/default-cache" />}
40+
>
41+
<div className="space-y-6">
42+
<InfoCard title="How it works">
43+
<ul className="list-disc list-inside space-y-1">
44+
<li>
45+
By default, Next.js uses{" "}
46+
<code className="bg-gray-200 dark:bg-gray-800 px-1 rounded">
47+
cache: &quot;force-cache&quot;
48+
</code>{" "}
49+
for fetch requests
50+
</li>
51+
<li>
52+
Data is cached indefinitely until the cache is manually cleared or
53+
the build is redeployed
54+
</li>
55+
<li>
56+
This is the most aggressive caching strategy - perfect for static
57+
or rarely-changing data
58+
</li>
59+
<li>
60+
The timestamp shows when this page was first rendered (it will
61+
remain the same on subsequent requests)
62+
</li>
63+
<li>
64+
Click &quot;Refresh Cache&quot; to manually revalidate the page
65+
cache and see fresh data
66+
</li>
67+
</ul>
68+
</InfoCard>
69+
70+
<div className="space-y-4">
71+
<div>
72+
<h2 className="text-lg font-semibold text-gray-900 dark:text-gray-100 mb-2">
73+
Character Data
74+
</h2>
75+
<div className="bg-gray-50 dark:bg-gray-900 rounded-lg p-4 space-y-2">
76+
<div>
77+
<span className="font-medium text-gray-700 dark:text-gray-300">
78+
Name:
79+
</span>{" "}
80+
<span className="text-gray-900 dark:text-gray-100">{name}</span>
81+
</div>
82+
{character.name.middle && (
83+
<div>
84+
<span className="font-medium text-gray-700 dark:text-gray-300">
85+
Middle Name:
86+
</span>{" "}
87+
<span className="text-gray-900 dark:text-gray-100">
88+
{character.name.middle}
89+
</span>
90+
</div>
91+
)}
92+
<div>
93+
<span className="font-medium text-gray-700 dark:text-gray-300">
94+
Last Name:
95+
</span>{" "}
96+
<span className="text-gray-900 dark:text-gray-100">
97+
{character.name.last}
98+
</span>
99+
</div>
100+
{character.occupation && (
101+
<div>
102+
<span className="font-medium text-gray-700 dark:text-gray-300">
103+
Occupation:
104+
</span>{" "}
105+
<span className="text-gray-900 dark:text-gray-100">
106+
{character.occupation}
107+
</span>
108+
</div>
109+
)}
110+
</div>
111+
</div>
112+
113+
<div>
114+
<h2 className="text-lg font-semibold text-gray-900 dark:text-gray-100 mb-2">
115+
Cache Information
116+
</h2>
117+
<div className="bg-gray-50 dark:bg-gray-900 rounded-lg p-4">
118+
<div>
119+
<span className="font-medium text-gray-700 dark:text-gray-300">
120+
Rendered at:
121+
</span>{" "}
122+
<span className="text-gray-900 dark:text-gray-100 font-mono text-sm">
123+
{timestamp}
124+
</span>
125+
</div>
126+
<div className="mt-2">
127+
<span className="font-medium text-gray-700 dark:text-gray-300">
128+
Cache Strategy:
129+
</span>{" "}
130+
<code className="bg-gray-200 dark:bg-gray-800 px-2 py-1 rounded text-sm">
131+
force-cache
132+
</code>
133+
</div>
134+
<div className="mt-2">
135+
<span className="font-medium text-gray-700 dark:text-gray-300">
136+
Revalidation:
137+
</span>{" "}
138+
<span className="text-gray-900 dark:text-gray-100">
139+
Never (indefinite)
140+
</span>
141+
</div>
142+
</div>
143+
</div>
144+
</div>
145+
146+
<div>
147+
<h2 className="text-lg font-semibold text-gray-900 dark:text-gray-100 mb-2">
148+
Code Example
149+
</h2>
150+
<CodeBlock>
151+
{`const response = await fetch(
152+
"https://api.sampleapis.com/futurama/characters/2",
153+
{
154+
cache: "force-cache",
155+
}
156+
);
157+
158+
// Or simply omit cache option (default behavior):
159+
const response = await fetch(
160+
"https://api.sampleapis.com/futurama/characters/2"
161+
);`}
162+
</CodeBlock>
163+
</div>
164+
</div>
165+
</ExampleLayout>
166+
);
167+
}

0 commit comments

Comments
 (0)