feat(examples): add Next.js App Router optimistic updates example#10997
feat(examples): add Next.js App Router optimistic updates example#10997guirab wants to merge 3 commits into
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughAdds a new ChangesNext.js App Router Optimistic Updates Example
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
No dependency changes detected. Learn more about Socket for GitHub. 👍 No dependency changes detected in pull request |
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@examples/react/nextjs-app-optimistic-updates/.eslintrc.cjs`:
- Around line 1-9: The current ESLint config only enables React rules, so the
example’s TypeScript `.tsx` files may fail to parse before linting runs. Update
the configuration in the `.eslintrc.cjs` for the Next.js optimistic updates
example by extending the Next.js TypeScript preset, using `next/core-web-vitals`
and `next/typescript` (or equivalent TypeScript parser setup) alongside the
existing React support. Make sure the config still covers the example’s React
and hooks rules while correctly handling TypeScript sources.
In `@examples/react/nextjs-app-optimistic-updates/app/api/todos/route.ts`:
- Around line 24-44: The POST handler in the todos route accepts unvalidated
input, so invalid or whitespace-only text can be pushed into the shared todos
array. Update POST to validate the parsed request body before creating newTodo,
using the existing request/json flow to reject missing, non-string, or
trimmed-empty text. Return a 400 response for invalid input and only call
todos.push after the text has been sanitized and confirmed valid.
- Around line 9-18: Move the runtime data and helper out of the route handler
module: `todos` and `getTodos` in `app/api/todos/route.ts` should be relocated
to a sibling module and imported where needed. Keep `route.ts` limited to HTTP
handlers/config exports only, and reference the shared module from the route
handler so Next’s route export rules are satisfied.
In `@examples/react/nextjs-app-optimistic-updates/components/TodoListCache.tsx`:
- Around line 42-65: The optimistic update flow in TodoListCache’s
onMutate/onError leaves the optimistic todo visible when previousTodos is
undefined, so track the created optimistic item’s id in the mutation context and
use it in onError to remove that specific row directly when there is no
snapshot. Keep the existing rollback to queryClient.setQueryData for the
previousTodos path, but in the no-snapshot path ensure the optimistic entry
added by queryClient.setQueryData is deleted immediately rather than waiting for
the refetch.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 9ed6d652-181d-48d6-86e8-8c6367564728
📒 Files selected for processing (14)
examples/react/nextjs-app-optimistic-updates/.eslintrc.cjsexamples/react/nextjs-app-optimistic-updates/.gitignoreexamples/react/nextjs-app-optimistic-updates/README.mdexamples/react/nextjs-app-optimistic-updates/app/api/todos/route.tsexamples/react/nextjs-app-optimistic-updates/app/get-query-client.tsexamples/react/nextjs-app-optimistic-updates/app/layout.tsxexamples/react/nextjs-app-optimistic-updates/app/page.tsxexamples/react/nextjs-app-optimistic-updates/app/providers.tsxexamples/react/nextjs-app-optimistic-updates/components/ApproachTabs.tsxexamples/react/nextjs-app-optimistic-updates/components/TodoListCache.tsxexamples/react/nextjs-app-optimistic-updates/components/TodoListUI.tsxexamples/react/nextjs-app-optimistic-updates/next.config.jsexamples/react/nextjs-app-optimistic-updates/package.jsonexamples/react/nextjs-app-optimistic-updates/tsconfig.json
| /** @type {import('eslint').Linter.Config} */ | ||
| module.exports = { | ||
| extends: ['plugin:react/jsx-runtime', 'plugin:react-hooks/recommended'], | ||
| settings: { | ||
| react: { | ||
| version: 'detect', | ||
| }, | ||
| }, | ||
| } |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win
Use the Next TypeScript ESLint preset here examples/react/nextjs-app-optimistic-updates/.eslintrc.cjs only enables React rules, so the example’s .tsx files can hit parse errors before any lint rules run. Extend next/core-web-vitals + next/typescript (or add @typescript-eslint/parser) so the TypeScript sources are linted.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@examples/react/nextjs-app-optimistic-updates/.eslintrc.cjs` around lines 1 -
9, The current ESLint config only enables React rules, so the example’s
TypeScript `.tsx` files may fail to parse before linting runs. Update the
configuration in the `.eslintrc.cjs` for the Next.js optimistic updates example
by extending the Next.js TypeScript preset, using `next/core-web-vitals` and
`next/typescript` (or equivalent TypeScript parser setup) alongside the existing
React support. Make sure the config still covers the example’s React and hooks
rules while correctly handling TypeScript sources.
There was a problem hiding this comment.
♻️ Duplicate comments (1)
examples/react/nextjs-app-optimistic-updates/app/api/todos/route.ts (1)
8-20: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick winHandle malformed JSON bodies explicitly.
request.json()can throw before thetextvalidation runs, so an invalid POST still turns into a 500 instead of the 400{ error }contract your client code expects.Suggested fix
export async function POST(request: Request) { - const body = (await request.json()) as unknown + let body: unknown + try { + body = await request.json() + } catch { + return NextResponse.json({ error: 'Invalid JSON body' }, { status: 400 }) + } const text = body !== null &&🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@examples/react/nextjs-app-optimistic-updates/app/api/todos/route.ts` around lines 8 - 20, The POST handler currently assumes request.json() always succeeds, so malformed JSON can escape the text validation and return a 500 instead of the expected 400 response. Update POST in the todos route to catch JSON parsing failures around request.json(), and return the same NextResponse.json({ error: 'text is required' }, { status: 400 }) contract when the body cannot be parsed or is invalid, keeping the existing text extraction/validation logic intact.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Duplicate comments:
In `@examples/react/nextjs-app-optimistic-updates/app/api/todos/route.ts`:
- Around line 8-20: The POST handler currently assumes request.json() always
succeeds, so malformed JSON can escape the text validation and return a 500
instead of the expected 400 response. Update POST in the todos route to catch
JSON parsing failures around request.json(), and return the same
NextResponse.json({ error: 'text is required' }, { status: 400 }) contract when
the body cannot be parsed or is invalid, keeping the existing text
extraction/validation logic intact.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: db5f2199-d0de-4a40-a664-fc0e657b95e0
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (5)
examples/react/nextjs-app-optimistic-updates/app/api/todos/data.tsexamples/react/nextjs-app-optimistic-updates/app/api/todos/route.tsexamples/react/nextjs-app-optimistic-updates/app/page.tsxexamples/react/nextjs-app-optimistic-updates/components/TodoListCache.tsxexamples/react/nextjs-app-optimistic-updates/components/TodoListUI.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
- examples/react/nextjs-app-optimistic-updates/app/page.tsx
- examples/react/nextjs-app-optimistic-updates/components/TodoListCache.tsx
- examples/react/nextjs-app-optimistic-updates/components/TodoListUI.tsx
🎯 Changes
Adds a new example demonstrating optimistic updates with Next.js App Router (App Directory).
This example was missing from the repo — the existing Next.js examples only cover prefetching
and streaming. Optimistic updates with App Router is a common real-world pattern that many
users ask about in discussions.
The example shows both approaches supported by TanStack Query v5:
Via UI variables (TodoListUI.tsx) — renders the pending item directly from
mutation.variables, simpler and requires no cache manipulation or rollback logic.Via cache manipulation (TodoListCache.tsx) — uses
onMutateto update the cacheoptimistically, with typed context and automatic rollback via
onErrorif the mutation fails.A tab switcher lets users compare both approaches side by side.
The API route simulates ~30% random failure to demonstrate the rollback behavior.
Implementation follows the conventions of
nextjs-app-prefetching.✅ Checklist
pnpm run test:pr.🚀 Release Impact
Summary by CodeRabbit
New Features
Bug Fixes
Documentation