{"slug": "react-js-use-hook-for-caching-problem", "title": "React.js ~use() hook for Caching Problem~", "summary": "The article explains that React's `use()` hook, which reads a promise, can cause an infinite re-render loop if the promise is created directly inside a Client Component, as a new promise is generated on every render. To stabilize the promise, the article recommends four approaches: creating the promise in a parent Server Component, using a module-level cache, employing a data fetching library like TanStack Query, or using React's built-in `cache()` function in Server Components. The key insight is that `use()` does not fetch data but reads a promise, which must have a stable identity across renders to avoid suspension loops.", "body_md": "This is where most tutorials stop. But if you try to use `use()`\n\nwith a promise created inside a Client Component, you will hit a subtle and frustrating bug.\n\n```\n// Bug: creates a new promise on every render\nfunction UserProfile({ userId }: { userId: string }) {\n  const user = use(fetchUser(userId)); // new promise every render\n  return <ProfileCard user={user} />;\n}\n```\n\n`fetchUser(userId)`\n\nreturns a new Promise object on every render. React sees a new promise, suspends again, and the component re-renders, creates another new promise, suspends again, infinite loop.\n\nuse() does not fetch data. It reads a promise. The promise must have a stable identity across renders. If you create a new promise on every render, you get an infinite suspension loop.\n\n**How to Stabilize the Promise**\n\nThere are several approaches, each suited to a different archtecture:\n\n**1. Create the promise in a parent component or Server Component**\n\n```\n// Server Component - promise created once, stable across renders\nexport default function UserPage({ params }: { params: { id: string } }) {\n  const userPromise = fetchUser(params.id);\n\n  return (\n    <Suspense fallback={<Skeleton />}>\n      <UserProfile userPromise={userPromise} />\n    </Suspense>\n  );\n}\n```\n\nNo `async/await`\n\nneeded, the promise is passed down unresolved. The Client Component unwraps it with use(). Server Components don't re-render, so the promise reference is inherently stable.\n\n**2. Use a module-level cache**\n\nFor Client Components that need to initiate fetches, cache the promise so the same reference is returned on subsequent calls:\n\n``` js\nconst cache = new Map<string, Promise<User>>();\n\nfunction fetchUserCached(id: string): Promise<User> {\n  if (!cache.has(id)) {\n    cache.set(id, fetchUser(id));\n  }\n  return cache.get(id)!;\n}\n\nfunction UserProfile({ userId }: { userId: string }) {\n  const user = use(fetchUserCached(userId));\n  return <ProfileCard user={user} />;\n}\n```\n\nSame arguments produce the same promise reference. No infinite loop.\n\nAvoid async in Cache Wrappers\n\nDo not mark your cache function as async. The async keyword always creates a new promise, even if you return a cached value. Use a synchronous function that stores and returns the original promise object.\n\n**3. Use a data fetching library**\n\nLibraries like TanStack Query or SWR handle caching, deduplication, and revalidation out of the box. They predate use() and solve a much broader problem - but they also add ~13kB gzipped and a provider wrapper. For a simple \"fetch once, display result\" pattern, use() with a 5-line cache function (option 2 above) does the job without the extra dependency. The library earns its keep when your UI has long-lived client state that needs to stay fresh: think dashboards that refetch on tab focus, lists with pagination, or mutations that should optimistically update related queries.\n\n**4. Use React's cache() in Server Components**\n\nReact provides a built-in\n\n`cache()`\n\nfunction for Server Components. It memoizes a function's return value for the lifetime of a single server request:\n\n``` js\nimport { cache } from \"react\";\n\nconst getUser = cache(async (id: string): Promise<User> => {\n  const res = await fetch(`/api/users/${id}`);\n  return res.json();\n});\n```\n\nMultiple components calling `getUser(\"123\")`\n\nduring the same render will share one fetch. The cache is scoped to the request, it resets on every new page load.\n\ncache() vs. useMemo\n\nBoth memoize. But cache() works across components in a server render (deduplication), while useMemo works within a single component across re-renders. cache() is for data fetching. useMemo is for computations. Different tools, different jobs.", "url": "https://wpnews.pro/news/react-js-use-hook-for-caching-problem", "canonical_source": "https://dev.to/kkr0423/reactjs-use-hook-for-caching-problem-2n47", "published_at": "2026-05-24 01:26:26+00:00", "updated_at": "2026-05-24 01:31:06.769243+00:00", "lang": "en", "topics": ["developer-tools", "web3"], "entities": ["React.js"], "alternates": {"html": "https://wpnews.pro/news/react-js-use-hook-for-caching-problem", "markdown": "https://wpnews.pro/news/react-js-use-hook-for-caching-problem.md", "text": "https://wpnews.pro/news/react-js-use-hook-for-caching-problem.txt", "jsonld": "https://wpnews.pro/news/react-js-use-hook-for-caching-problem.jsonld"}}