← Back to list

add-caching
by tech-with-seth
React Router 7 starter with Polar.sh, BetterAuth, Prisma, and Tailwind
⭐ 1🍴 0📅 Jan 25, 2026
SKILL.md
name: add-caching description: Add client-side caching with stale-while-revalidate strategy. Use when optimizing page load performance or reducing server requests.
Add Caching
Adds client-side caching using remix-client-cache with a stale-while-revalidate (SWR) strategy.
When to Use
- Improving page load performance
- Reducing server requests for frequently accessed data
- Caching loader data across navigations
- User asks to "add caching", "improve performance", or "cache data"
How SWR Works
- Returns cached (stale) data immediately
- Refreshes data in the background
- Hot-swaps updated data when available
Step 1: Configure Global Storage
Location: app/entry.client.tsx
import { configureGlobalCache } from "remix-client-cache";
// Use localStorage for persistent cache
configureGlobalCache(() => localStorage);
// Or sessionStorage (cleared when tab closes)
configureGlobalCache(() => sessionStorage);
Step 2: Create Cached Client Loader
import { createClientLoaderCache } from "remix-client-cache";
import type { Route } from "./+types/my-route";
export async function loader({ request }: Route.LoaderArgs) {
const data = await fetchData();
return { data };
}
// Generate cached client loader
export const clientLoader = createClientLoaderCache({
loader,
// Optional: custom cache key
key: (args) => `products-${args.params.id}`,
});
// Enable client loader hydration
clientLoader.hydrate = true;
Step 3: Use Cached Data in Component
Option A: useCachedLoaderData Hook
import { useCachedLoaderData } from "remix-client-cache";
import type { Route } from "./+types/my-route";
export default function MyRoute() {
const data = useCachedLoaderData<typeof loader>();
return (
<div>
<h1>{data.title}</h1>
</div>
);
}
Option B: CacheRoute Wrapper
import { CacheRoute } from "remix-client-cache";
import type { Route } from "./+types/my-route";
export default function MyRoute() {
return (
<CacheRoute>
{(data) => (
<div>
<h1>{data.title}</h1>
</div>
)}
</CacheRoute>
);
}
Cache Invalidation
After Mutations
import { decacheClientLoader } from "remix-client-cache";
import type { Route } from "./+types/my-route";
export async function clientAction({ request }: Route.ClientActionArgs) {
const result = await submitForm(request);
// Clear the cache for this route
await decacheClientLoader();
return result;
}
Manual Invalidation
import { invalidateCache, useCacheInvalidator } from "remix-client-cache";
// Direct invalidation
await invalidateCache("my-cache-key");
await invalidateCache(["key1", "key2"]);
// Hook-based invalidation
function RefreshButton() {
const invalidate = useCacheInvalidator();
return (
<button onClick={() => invalidate("my-cache-key")}>
Refresh
</button>
);
}
Manual Cache Wrapper
For more control:
import { cacheClientLoader } from "remix-client-cache";
import type { Route } from "./+types/my-route";
export async function clientLoader(args: Route.ClientLoaderArgs) {
return cacheClientLoader(args, {
key: `user-${args.params.id}`,
adapter: () => sessionStorage,
});
}
clientLoader.hydrate = true;
Storage Options
| Storage | Persistence | Use Case |
|---|---|---|
| localStorage | Persists across sessions | User preferences, stable data |
| sessionStorage | Cleared when tab closes | Sensitive or session-specific data |
| In-memory | Cleared on reload | Development, testing |
Best Practices
- Configure storage early - Set up in
entry.client.tsxbefore hydration - Use meaningful cache keys - Include dynamic parameters:
products-${productId} - Invalidate after mutations - Always clear cache in clientAction
- Set hydrate = true - Enable proper hydration for cached data
- Consider data freshness - Not all data should be cached
When NOT to Cache
- Real-time data that changes frequently
- User-specific sensitive data (with localStorage)
- Data that must always be fresh
- Small, fast API responses
Anti-Patterns
- Forgetting to invalidate cache after mutations
- Using localStorage for sensitive data
- Caching without considering data freshness
- Not setting
hydrate = trueon clientLoader
Full Reference
See .github/instructions/client-side-caching.instructions.md for comprehensive documentation.
Score
Total Score
65/100
Based on repository quality metrics
✓SKILL.md
SKILL.mdファイルが含まれている
+20
✓LICENSE
ライセンスが設定されている
+10
○説明文
100文字以上の説明がある
0/10
○人気
GitHub Stars 100以上
0/15
✓最近の活動
1ヶ月以内に更新
+10
○フォーク
10回以上フォークされている
0/5
✓Issue管理
オープンIssueが50未満
+5
✓言語
プログラミング言語が設定されている
+5
✓タグ
1つ以上のタグが設定されている
+5
Reviews
💬
Reviews coming soon

