This Week In React #273: RedwoodSDK, Async React, TanStack Start SSR, Vite 8, Temporal Stage 4, and More

Published on 18.03.2026

bash — 80×24$pnpm dev▶ ready on localhost:3000$git commit -m "feat: og images"$npx tsc --noEmit✓ 0 errorsCODING

RedwoodSDK: From RedwoodJS to a Cloudflare-Native React Framework

TLDR: RedwoodJS has evolved into RedwoodSDK, a server-first React framework built entirely for Cloudflare Workers, featuring RSC support, realtime capabilities, and a zero-magic philosophy.

Summary: The Redwood team has made a bold pivot. Rather than continuing to iterate on the traditional full-stack RedwoodJS architecture, they have launched RedwoodSDK as a new direction that embraces Cloudflare as a unified platform. The framework starts as a Vite plugin that unlocks SSR, React Server Components, Server Functions, and realtime features out of the box. Its standards-based router supports middleware and interruptors for fine-grained control over every request and response. With built-in access to Cloudflare Workers, D1 databases, R2 storage, Queues, and AI services, plus full local emulation via Miniflare, the development experience closely mirrors production. The original RedwoodJS remains fully supported and maintained, so existing projects are not being abandoned. RedwoodSDK's philosophy centers on composability over configuration, web-first architecture, and an explicit request/response cycle with no hidden magic.

Key takeaways:

  • RedwoodSDK is a Cloudflare-native, server-first React framework with RSC, SSR, and realtime support
  • Built as a Vite plugin with standards-based routing, middleware, and interruptors
  • RedwoodJS continues to receive active maintenance and support
  • Philosophy emphasizes zero magic, composability, and web standards
  • Deploys in seconds with simple commands to Cloudflare Workers

Why do I care: If you have been watching the RSC framework space and feeling overwhelmed by the opinions baked into larger frameworks, RedwoodSDK offers a refreshingly minimal alternative. The Cloudflare-native approach means you get edge-first performance and integrated infrastructure services without juggling multiple providers. For teams already on Cloudflare or considering it, this could be the most straightforward path to production-grade RSC apps.

From RedwoodJS to RedwoodSDK


Less Code, More Power: Why Aha! Rolled Their Own RSC Framework

TLDR: The Aha! engineering team replaced Gatsby with a custom React Server Components framework built in under 1,000 lines of code, reducing JavaScript payloads by 90% and time-to-interactive by over 80%.

Summary: The Aha! team faced a common problem: their Gatsby-powered website had grown to ship enormous amounts of JavaScript for every page, and the static site generation model meant every content typo required a full redeploy. Rather than migrating to another opinionated framework, they built their own mini RSC framework using Vite's new official RSC plugin and React 19. The article walks through the entire architecture, showing how the RSC, SSR, and client entry points fit together in remarkably little code. The key enabler is that React 19 and the Vite RSC plugin have absorbed so much of the complexity that frameworks used to handle, including asset loading, CSS management, and document head manipulation, that a custom framework becomes genuinely feasible. The team added file-based routing, client-side navigation, static site generation support, and Server Functions while staying under 1,000 lines total. The article provides a compelling comparison of framework philosophies across Next.js, React Router, TanStack Start, Waku, and RedwoodSDK, helping readers understand when rolling your own makes sense versus adopting an existing solution.

Key takeaways:

  • React 19 and Vite's RSC plugin have dramatically lowered the barrier to building custom frameworks
  • A fully functional RSC framework can be built in under 50 lines of core code
  • The approach reduced JavaScript/JSON payloads by 90% and time-to-interactive by over 80%
  • Custom frameworks offer backward-compatible migration paths that off-the-shelf solutions cannot
  • The article includes working code examples for every piece of the framework architecture

Why do I care: This is one of the most practical RSC articles published to date. Even if you never build your own framework, understanding how RSC, SSR, and client hydration fit together at this level of detail makes you a better React developer. The fact that the Vite RSC plugin makes this accessible means the RSC ecosystem is maturing rapidly, and the mental model it teaches transfers directly to understanding what Next.js, TanStack Start, and others do under the hood.

Less code, more power: Why we rolled our own React Server Components framework


From Fiber to Async React: The Complete Mental Model

TLDR: A comprehensive deep-dive into how React Fiber enabled the entire Async React story, from Suspense and transitions to optimistic updates and actions, reframing these APIs as expressions of a single unified model.

Summary: This article traces the entire arc from React's stack reconciler through Fiber to the modern Async React paradigm. It begins by showing the limitations of the old synchronous rendering model, where React had to complete the entire component tree in one uninterrupted pass. The rewrite to Fiber introduced interruptible renders, cooperative scheduling, and prioritization by modeling each component as a lightweight unit of work that can be paused, resumed, or discarded. The article then demonstrates how this foundation enabled every major React API introduced in versions 18 and 19: Suspense catches thrown promises during the interruptible reconciliation phase, transitions mark low-priority updates so urgent interactions stay responsive, and optimistic state lets the UI reflect user intent before async work completes. The key insight is that these features were documented and taught in isolation but are actually different expressions of the same underlying model. The article introduces the concept of "async first" components that assume data is available at render time, use Suspense for loading coordination, and wrap mutations in transitions, eliminating the need for useEffect-based data fetching entirely. It extends this to async-first component libraries with action props and suspense-enabled routers.

Key takeaways:

  • Async React is not a single feature but a unified mental model made possible by Fiber's architecture
  • Async-first components assume data availability and let React coordinate loading, errors, and transitions
  • Action props on component libraries enable automatic pending states, disabled states, and error propagation
  • Suspense-enabled routers wrap navigations in transitions, keeping current UI responsive while preparing the next route
  • The model extends beyond web to React Native and other renderers

Why do I care: If you have been adopting React 18 and 19 features piecemeal, this article connects the dots in a way that fundamentally changes how you architect applications. Understanding that Suspense, transitions, optimistic updates, and actions are all part of one coordinated system means you can design component hierarchies that leverage React's scheduling instead of fighting it. This is the mental model shift that separates incremental adoption from truly modern React architecture.

From Fiber to Async React


Two React Design Choices Developers Hate But Cannot Avoid

TLDR: Ryan Carniato (creator of SolidJS) explains why React's deferred state commits and dependency arrays on effects are not arbitrary design choices but fundamental invariants that every UI framework must eventually confront.

Summary: In a remarkably candid article, Ryan Carniato shares how working on Solid 2.0 led him to an uncomfortable realization: React was right about the two most criticized aspects of its API. The first invariant is that async must be isolated from commits. In a synchronous world, Signals keep state and derived state perfectly in sync, giving developers a strong sense of safety. But the moment any derived value becomes async, that guarantee collapses. If the UI should remain consistent while waiting for an async derivation to resolve, you must delay the commit, and once you delay the UI commit, you must delay the data commit too, or the two drift apart. React's deferred state updates, which developers found counterintuitive, were an early acknowledgment of this truth. The second invariant is that effect dependencies must be known at computation time, not discovered during execution. When async enters the graph, effects that discover dependencies dynamically risk running with partial or speculative state. React's dependency arrays, crude as they seemed, ensured all dependencies were declared upfront. Carniato argues these are not React-isms but physics of UI that Vue, Solid, and every other framework must eventually respect. Compilers cannot solve this because async is a runtime phenomenon.

Key takeaways:

  • Deferred state commits and dependency arrays are invariants of any consistent UI system, not React quirks
  • Signals hide the problem in synchronous scenarios but break down when async enters the graph
  • Async forces commit isolation: you cannot let async work interleave with synchronous commits
  • Effect dependencies must be separable from effect execution to handle async correctly
  • Solid 2.0 is adopting these same invariants from a position of strength, not mimicry

Why do I care: This is a rare moment of cross-framework intellectual honesty from one of the most respected voices in the reactive programming space. If you have ever questioned why React works the way it does, or wondered whether Signals-based frameworks have fundamentally better answers, this article provides the deepest explanation available. Understanding these invariants makes you a better architect regardless of which framework you use.

Two React Design Choices Developers Don't Like But Can't Avoid


5x SSR Throughput: Profiling Hot Paths in TanStack Start

TLDR: The TanStack Start team achieved a 5.5x improvement in SSR throughput (427 to 2,357 req/s) and 9.9x faster average latency through systematic profiling and four key optimization patterns.

Summary: This deeply technical article documents how the TanStack Start team systematically improved their SSR performance through a repeatable process of measuring under load, CPU profiling with flamegraphs, and removing entire categories of cost from the server hot path. The work spanned over 20 pull requests, each validated with before/after comparisons on dedicated benchmark endpoints. The four highest-impact findings were: URL construction and parsing is expensive when done per-link per-request and can be avoided with cheap predicate checks; SSR does not need reactivity since the server renders once per request with no subscriptions or structural sharing needed; server-only fast paths gated behind build-time constants like isServer allow different optimization strategies for server and client without inflating bundle size; and the delete operator can be surprisingly expensive because it changes object shapes and degrades V8's inline caches. An independent benchmark by Matteo Collina confirmed the improvements, showing the server going from 75% success rate under load to 100% with 2.2x throughput and 231x faster average latency.

Key takeaways:

  • Measure under realistic sustained load, not microbenchmarks, to find real bottlenecks
  • Avoid URL parsing in hot paths by using cheap predicates to identify internal navigation
  • Gate reactive machinery behind build-time isServer flags to skip subscriptions during SSR
  • Prefer setting properties to undefined over using delete in performance-sensitive code
  • Use feature-focused benchmark endpoints that exaggerate specific subsystems for unambiguous profiling

Why do I care: Even if you do not use TanStack Start, the optimization patterns here are universally applicable. The insight that SSR should be treated as a simple function rather than a reactive system is particularly valuable for anyone building server-rendered React applications. The methodology itself, isolating subsystems with dedicated endpoints and validating each change with flamegraphs, is a masterclass in performance engineering you can apply to any framework.

5x SSR Throughput: Profiling SSR Hot Paths in TanStack Start


Next.js 16.2: AI Agent Improvements

TLDR: Next.js 16.2 focuses on making applications more accessible to AI coding agents, with bundled documentation, browser log forwarding to terminal, dev server lock files, and experimental agent DevTools.

Summary: This release takes a distinctly different direction for a framework update by focusing almost entirely on the developer experience when working with AI coding agents. The headline feature is that create-next-app now includes an AGENTS.md file by default, pointing agents to version-matched Next.js documentation bundled directly in the npm package. This approach achieved a 100% pass rate on Next.js evals compared to 79% for skill-based retrieval approaches, based on the insight that always-available context outperforms on-demand retrieval because agents often fail to recognize when they should search for documentation. Browser log forwarding now sends client-side errors to the terminal by default during development, which is critical for agents that operate primarily through CLI. The new dev server lock file prevents the common agent mistake of starting a second dev server. The experimental next-browser CLI tool is perhaps the most forward-looking feature, exposing React DevTools data, component trees, props, hooks, PPR shell analysis, and screenshots as structured text that agents can parse and reason about.

Key takeaways:

  • Bundled documentation in node_modules achieves 100% agent eval pass rate versus 79% for retrieval-based approaches
  • Browser errors now forward to terminal by default, enabling agent-powered debugging
  • Dev server lock files prevent agents from accidentally starting duplicate servers
  • Experimental next-browser CLI exposes React DevTools and diagnostics as structured text for agents
  • The PPR shell analysis feature can help agents optimize static versus dynamic rendering boundaries

Why do I care: Whether you are enthusiastic or skeptical about AI-assisted development, this release signals where framework authors think the industry is heading. The practical insight about bundled documentation outperforming retrieval is immediately applicable to any project. And the next-browser tool's ability to expose component trees and PPR analysis as structured text hints at a future where agents can meaningfully participate in performance optimization, not just code generation.

Next.js 16.2: AI Improvements


Vite 8: The Rolldown Era Begins

TLDR: Vite 8 ships with Rolldown as its single unified Rust-based bundler, replacing the dual esbuild/Rollup architecture with 10-30x faster builds while maintaining full plugin compatibility.

Summary: This is the most significant architectural change in Vite since version 2. Vite 8 replaces its longstanding dual-bundler approach, where esbuild handled development and Rollup handled production, with Rolldown as a single unified Rust-based bundler. The migration was deliberate and community-driven, starting with a separate rolldown-vite preview package that allowed early adopters to test the integration on real codebases. Real-world results from the preview period are impressive: Linear saw production builds drop from 46 seconds to 6 seconds, Ramp achieved 57% build time reduction, and Beehiiv saw 64% improvement. With Vite 8, the project becomes the entry point to an end-to-end toolchain with closely collaborating teams covering the build tool, bundler, and compiler layers. Additional features include integrated devtools, built-in tsconfig paths support, emitDecoratorMetadata support, Wasm SSR support, and browser console forwarding. The release is accompanied by @vitejs/plugin-react v6 which uses Oxc for React Refresh transforms, dropping the Babel dependency entirely.

Key takeaways:

  • Rolldown replaces both esbuild and Rollup as a single unified bundler with 10-30x faster builds
  • Most existing Vite plugins work out of the box with Vite 8
  • Real-world production build improvements: Linear 46s to 6s, Ramp 57% reduction, Beehiiv 64% reduction
  • @vitejs/plugin-react v6 drops Babel dependency by using Oxc for React Refresh transforms
  • Experimental full bundle mode coming next, showing 3x faster dev server startup in preliminary results

Why do I care: If you use Vite, this is the upgrade you have been waiting for. The unification of the bundler pipeline eliminates an entire class of edge cases around inconsistent module handling between development and production. The performance improvements are not theoretical; they translate directly to faster CI pipelines and shorter feedback loops. And with the React plugin dropping Babel, your installation footprint gets meaningfully smaller.

Vite 8.0 is out!


Announcing Vite+ Alpha: A Unified Web Development Toolchain

TLDR: VoidZero open-sources Vite+ under MIT, a single binary that unifies Vite, Vitest, Oxlint, Oxfmt, Rolldown, and tsdown with a task runner, Node.js version management, and package manager integration.

Summary: Vite+ is an ambitious attempt to collapse the sprawling JavaScript toolchain into a single coherent experience. Rather than juggling separate tools for development, testing, linting, formatting, and building, Vite+ provides one binary (vp) and one configuration file. It manages your Node.js version and package manager automatically, runs Vite for development, Vitest for testing, Oxlint for linting, Oxfmt for formatting, and Rolldown for production builds. The new Vite Task runner provides automated input tracking that fingerprints files to determine what should be cached, dependency-aware execution across monorepo workspaces, and a familiar CLI that mirrors pnpm run. Performance numbers are significant: 1.6x to 7.7x faster production builds compared to Vite 7, Oxlint running 50x to 100x faster than ESLint, and Oxfmt at 30x faster than Prettier. Perhaps the most notable announcement is the licensing decision. VoidZero initially considered a paid license but ultimately chose MIT, concluding that Vite+ can only achieve its mission when it is truly free and open source.

Key takeaways:

  • Single binary unifying Vite, Vitest, Oxlint, Oxfmt, Rolldown, and tsdown under one configuration file
  • Vite Task provides automated caching, dependency-aware execution, and monorepo support
  • Fully MIT licensed after community feedback convinced VoidZero to drop paid licensing plans
  • Compatible with all frameworks in Vite's ecosystem including React, Vue, and Svelte
  • Migration from existing Vite projects is straightforward via vp migrate command

Why do I care: The JavaScript toolchain fragmentation tax is real. Every new project means choosing and configuring a version manager, package manager, bundler, test runner, linter, and formatter, then keeping them all in sync. Vite+ takes a credible shot at making that a single install. The MIT licensing decision removes the biggest adoption concern, and the performance numbers from VoidZero's Rust-based tools are genuinely impressive.

Announcing Vite+ Alpha


TC39 Advances Temporal to Stage 4

TLDR: The Temporal API has officially reached Stage 4 at TC39's March 2026 meeting, becoming part of ECMAScript 2026 after nearly a decade of development, with browser support already shipping in Firefox, Chrome, and Edge.

Summary: JavaScript's most painful API gap is finally closing. The Temporal proposal, a modern replacement for the notoriously broken Date object, has reached Stage 4 after a nine-year journey involving contributors from Bloomberg, Igalia, Google, Microsoft, and many independents. Temporal introduces immutable date and time types under a new global namespace, with specialized constructors for different use cases: ZonedDateTime for time-zone-aware operations with daylight saving correctness, Instant for exact moments in nanosecond precision, and a family of Plain types for wall-clock values without time zone context. The implementation story is remarkable in its own right. A shared Rust library called temporal_rs was collaboratively built by Google's internationalization team and the Boa engine project, passing 100% of the approximately 4,500 test suite entries and serving multiple JavaScript engines. Bloomberg's companion article provides rich historical context, tracing how Date was a straight port of Java's Date class during Brendan Eich's 10-day sprint in 1995, and how the limitations forced an ecosystem of third-party libraries accumulating over 100 million weekly downloads. Support has already landed in Firefox 139, Chrome 144, Edge 144, and TypeScript 6.0 Beta.

Key takeaways:

  • Temporal is the biggest addition to ECMAScript since ES2015, with approximately 4,500 tests in Test262
  • Already supported in Firefox 139, Chrome 144, Edge 144, and TypeScript 6.0 Beta
  • Introduces immutable types: ZonedDateTime, Instant, PlainDate, PlainTime, PlainDateTime, and Duration
  • The shared temporal_rs Rust library is an unprecedented cross-engine collaboration
  • Several other TC39 proposals also advanced, including Import text (Stage 3) and Error stack accessor (Stage 2.7)

Why do I care: If you have ever wrestled with JavaScript Date, reached for Moment.js or date-fns, or dealt with daylight saving bugs in production, Temporal is the fix you have been waiting for. It ships with the browser, which means no more bundling timezone data or downloading hundreds of kilobytes of date libraries. The immutable, type-safe API design means entire categories of date-related bugs simply cannot occur. Start learning the API now because it is already available in major browsers.

TC39 Advances Temporal to Stage 4


Oxlint JS Plugins Alpha: 80% of ESLint Users Can Switch Now

TLDR: Oxlint's JavaScript plugins have reached alpha, providing an ESLint-compatible plugin API that lets teams run existing ESLint plugins within Oxlint at 4.8x to 100x the speed.

Summary: Oxlint has crossed a critical adoption threshold. With the alpha release of JS plugins, the tool now supports running most existing ESLint plugins without modification, meaning teams can migrate without rewriting their lint rules. The conformance numbers are impressive: 100% pass rate against ESLint's own built-in rule test suite, 100% against React hooks and React Compiler rules, 99.99% against ESLint Stylistic, and 100% against Testing Library. A real-world benchmark migrating the Node.js repository from ESLint to Oxlint showed 98 JS lint rules running in 21 seconds versus ESLint's 1 minute and 43 seconds, a 4.8x speedup. For projects heavy on TypeScript-ESLint or eslint-plugin-import, gains can be much larger, with one user reporting a 16x speedup on a 2 million line codebase. The performance secret is a new "raw transfer" mechanism for communicating between Rust and JS that reduces the cost of crossing the language boundary almost to zero. Current limitations include incomplete support for framework-specific file formats like Svelte and Vue, no custom type-aware rules, and known issues on Windows.

Key takeaways:

  • 100% pass rate against ESLint's built-in rule test suite and React hooks test suite
  • Most existing ESLint plugins work without modification via the ESLint-compatible plugin API
  • 4.8x to 100x speedups depending on project size and plugin usage
  • "Raw transfer" mechanism nearly eliminates the Rust/JS communication overhead
  • Migration tool available via npx @oxlint/migrate or coding agent skill

Why do I care: Linting speed directly affects your development feedback loop and CI pipeline costs. If your ESLint configuration takes more than a few seconds, Oxlint with JS plugins is now a realistic drop-in replacement that could cut that time by an order of magnitude. The fact that existing plugins work without modification removes the biggest migration barrier.

Oxlint JS Plugins Alpha


Vitest 4.1: Tags, Agent Reporter, and Native Module Runner

TLDR: Vitest 4.1 ships with test tags for organizing and filtering tests, an experimental native module runner mode, enhanced Playwright trace integration, and an agent-optimized reporter for AI coding workflows.

Summary: Vitest 4.1 is a feature-dense release that adds support for Vite 8 and introduces several capabilities that improve both human and AI-assisted testing workflows. Test tags let you label tests with metadata like "db" or "flaky" and attach configuration such as custom timeouts or retry counts, then filter them using a pytest-inspired syntax with boolean operators and wildcards. The experimental viteModuleRunner flag disables Vite's module runner entirely, executing tests with native Node.js import for closer-to-production behavior and faster startup. The new agent reporter automatically activates when running inside AI coding agents, showing only failed tests and their errors to minimize token usage. Other notable additions include aroundAll and aroundEach hooks for wrapping tests in database transactions or tracing contexts, vi.defineHelper for cleaner stack traces from shared test utilities, async leak detection via node:async_hooks, and a new builder pattern for test.extend that supports full TypeScript type inference. The GitHub Actions reporter now generates automatic job summaries with test statistics and flaky test highlights.

Key takeaways:

  • Test tags with pytest-inspired filtering syntax and configurable per-tag options
  • Experimental native module runner mode for closer-to-production test execution
  • Agent reporter reduces token usage by showing only failures when run inside AI coding agents
  • New aroundEach and aroundAll hooks for wrapping tests in transactions or contexts
  • Automatic GitHub Actions job summaries with flaky test highlighting

Why do I care: The tags feature alone is worth the upgrade for any team managing a large test suite. Being able to mark tests as "flaky" with automatic retries on CI, or tag database tests with longer timeouts, eliminates a ton of boilerplate configuration. The native module runner experiment is also worth watching closely; running tests without Vite's sandbox means catching production-environment issues earlier in the development cycle.

Announcing Vitest 4.1


Base UI v1.3.0: Stable Drawer and Extensive Fixes

TLDR: Base UI v1.3.0 promotes Drawer to stable, adds automatic aria-labelledby support across form components, and ships dozens of accessibility and interaction fixes across its component library.

Summary: This release graduates the Drawer component from preview to stable, making it a first-class citizen in the Base UI library with improved touch interaction handling, cross-axis scrolling during gestures, and a new SwipeArea part for explicit swipe regions. Across the library, Checkbox, Radio Group, and Switch components gain automatic aria-labelledby support, reducing the accessibility boilerplate developers need to write. The Combobox receives significant attention with fixes for SSR ARIA attributes, virtualized grid navigation, and a new InputGroup and Label part. Navigation Menu gets content transitions via Viewport, and Menu receives fixes for nested inline menus, hover interactions, and close propagation. Performance optimizations land in useHover hooks and safePolygon, and the release addresses shadow DOM dismissal, nested hoverable popup edge cases, and device pixel grid snapping for anchor positioning.

Key takeaways:

  • Drawer component promoted from preview to stable with improved touch handling
  • Automatic aria-labelledby support added to Checkbox, Radio Group, and Switch
  • Combobox gets SSR ARIA fixes, virtualized grid navigation improvements, and new parts
  • Performance optimizations in hover hooks and safe polygon calculations
  • Extensive fixes for nested menus, shadow DOM dismissal, and anchor positioning

Why do I care: If you are building a design system on top of Base UI or evaluating unstyled component libraries, v1.3.0 represents a significant maturity milestone. The Drawer going stable and the automatic ARIA support across form components reduce the amount of accessibility work you need to do manually. The sheer volume of edge case fixes in this release suggests the library is being battle-tested in serious production environments.

Base UI v1.3.0


Making Sense of the Key Prop in React

TLDR: An interactive deep-dive into how React's reconciliation algorithm uses keys to track element identity, with live demos showing exactly why index-as-key causes state bugs.

Summary: This article takes the most commonly misunderstood React concept and makes it tangible through interactive demonstrations. It starts with the fundamental problem: when a list is reordered, React comparing elements by position alone cannot distinguish between an item being moved, deleted, or replaced. Without keys, React reuses component instances at each position and merely patches the props, which means internal state like form inputs or "added to cart" indicators stick to positions rather than following their logical items. The article includes live demos where you can sort a product list and watch the "Added" button incorrectly jump to a different product. It then explains how keys give React stable identity for each item, enabling correct tracking of moves, insertions, and removals. The treatment of keys on non-list components is particularly illuminating: it demonstrates how two components of the same type at the same position share state unless given different keys, which is a powerful pattern for forcing remounts. The article also covers why index-as-key merely suppresses the warning without fixing the underlying issue, and why Math.random as a key causes catastrophic remounting on every render.

Key takeaways:

  • Without keys, React tracks elements by position and reuses component instances, causing state to stick to wrong items
  • Keys provide stable identity that lets React correctly track moves, insertions, and removals
  • Keys on non-list components can force remounts, useful for resetting component state
  • Index-as-key only suppresses warnings; it fails whenever list items have internal state
  • Math.random as key causes full list recreation on every render

Why do I care: Even experienced React developers carry misconceptions about keys. The interactive demos in this article make the reconciliation behavior visceral in a way that documentation alone cannot. Understanding keys at this depth prevents subtle state bugs that are notoriously difficult to debug in production, especially in forms, shopping carts, and any UI with reorderable lists.

Making sense of 'key' prop in React