perf: dedupe getShared with React cache and parallelize updates page fetches#151
perf: dedupe getShared with React cache and parallelize updates page fetches#151hugodemenez wants to merge 1 commit into
Conversation
…fetches - Wrap getShared in React.cache() on the shared page so generateMetadata and the page component share a single request per render instead of making two identical DB transactions (which also double-incremented the view counter). - Replace sequential getPost + getAdjacentPosts calls on the updates page with Promise.allSettled to shave request latency. Co-authored-by: Hugo Demenez <hugodemenez@users.noreply.github.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
🤖 Automated Code ReviewHere is a concise review based on PR review summaryUpdates page (
|
There was a problem hiding this comment.
Pull request overview
This PR targets server-render performance in two Next.js App Router pages by reducing redundant data-fetch work and improving fetch concurrency.
Changes:
- Deduplicates
/shared/[slug]data fetching by wrappinggetSharedwith Reactcache()sogenerateMetadataand the page reuse the same request-scoped result. - Parallelizes
/updates/[slug]fetching of the main post and adjacent navigation data usingPromise.allSettled.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| app/[locale]/shared/[slug]/page.tsx | Adds a cached wrapper around getShared and uses it in both generateMetadata and the page component to avoid duplicate DB work / double view increments. |
| app/[locale]/(landing)/updates/[slug]/page.tsx | Runs getPost and getAdjacentPosts concurrently to reduce end-to-end latency of the updates page render. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const [postResult, adjacentPostsResult] = await Promise.allSettled([ | ||
| getPost(slug, locale), | ||
| getAdjacentPosts(slug, locale), | ||
| ]); | ||
|
|
||
| try { | ||
| post = await getPost(slug, locale); | ||
| } catch (postError) { | ||
| console.error("Error fetching post data:", postError); | ||
| if (postResult.status === "rejected") { | ||
| console.error("Error fetching post data:", postResult.reason); | ||
| notFound(); | ||
| } |
| const [postResult, adjacentPostsResult] = await Promise.allSettled([ | ||
| getPost(slug, locale), | ||
| getAdjacentPosts(slug, locale), | ||
| ]); |
Problem
Two performance issues in the Next.js pages:
Shared page (
/shared/[slug]) —getShared(slug)was called twice per request: once ingenerateMetadataand again in the page component. SincegetSharedruns a Prisma transaction that queries the DB for trades, tick details, and groups (and also increments the view counter), the duplicate call doubled both latency and cost per page load, and inflated view counts.Updates page (
/updates/[slug]) —getPostandgetAdjacentPostsare independent data fetches but were running sequentially, adding unnecessary latency.Solution
Shared page — React
cache()deduplicationWrapped
getSharedwith React'scache()at module scope (getCachedShared). Reactcachededuplicates calls with the same arguments within a single server render, sogenerateMetadataand the page component now share a single DB call.Updates page —
Promise.allSettledparallelizationReplaced the sequential
await getPost()/await getAdjacentPosts()withPromise.allSettled([...])so both fetches run concurrently.allSettledpreserves the existing error-handling behavior: a failedgetAdjacentPostsgracefully falls back to{ previous: null, next: null }without blocking the page render.Changed files
app/[locale]/shared/[slug]/page.tsxapp/[locale]/(landing)/updates/[slug]/page.tsx