feat(examples): add Next.js App Router optimistic updates example - #10997
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (19)
💤 Files with no reviewable changes (11)
🚧 Files skipped from review as they are similar to previous changes (6)
Included review availability: Your plan includes up to 10 reviews per rolling hour; 9 remain after this review. 📝 WalkthroughWalkthroughAdds a runnable Next.js App Router example with an in-memory todos API, React Query server hydration, and two client-side optimistic update approaches: mutation variables and cache manipulation with rollback. ChangesNext.js optimistic updates example
Estimated code review effort: 3 (Moderate) | ~20 minutes Merge Risk: ⚪ Minimal · up to This documentation/example-only change introduces no actionable merge-blocking risk at the current head and is merge-ready after normal checks and review. Sequence Diagram(s)sequenceDiagram
participant User
participant TodoListCache
participant RouteHandler
participant TodoStore
User->>TodoListCache: Submit todo
TodoListCache->>TodoListCache: Snapshot and update cache
TodoListCache->>RouteHandler: POST /api/todos
RouteHandler->>TodoStore: Store todo on success
RouteHandler-->>TodoListCache: Return success or error
TodoListCache->>TodoListCache: Restore on error or invalidate on settle
🚥 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
|
Note GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer. |
|
View your CI Pipeline Execution ↗ for commit 8f010b7
☁️ Nx Cloud last updated this comment at |
🎯 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
Documentation
Chores