Compare React versions and see exactly what changes, what requires action, and what you can start using.
→
30Changes
6Breaking
14Actions
9Features
0Migration tools
Analyze your project
Paste your package.json
UpgradePath detects relevant tools and selects them automatically.
Local only
Analyzed locally in your browser. Nothing is uploaded.
Project setup
What does your project use?
Select the tools in your project to include relevant dependency updates in this guide.
Breaking Changes
ReactDOM.render should be replaced with createRoot
Action required
breakinghigh impact
React 18 introduces the new root API. Applications that continue using ReactDOM.render run in React 17 compatibility mode and cannot use the new React 18 concurrent features.
Move callback behavior to an appropriate application mechanism such as an effect. React notes that there is no universal one-to-one replacement for the old render callback.
Missing or extra text content during hydration is treated as an error rather than a warning. React may fall back to client rendering up to the closest Suspense boundary instead of attempting to patch individual mismatched nodes.
Migration
Fix server/client markup mismatches instead of relying on React to patch them during hydration.
Move post-render work to an appropriate mechanism such as an effect, a ref callback, or another API suited to the specific use case. React does not provide a one-to-one replacement for the old render callback.
Transitions separate urgent and non-urgent updates
featuremedium impact
React 18 introduces startTransition and useTransition for marking state updates as non-urgent so urgent interactions such as typing can remain responsive.
React 18 introduces useDeferredValue for deferring updates to non-urgent parts of the UI. Unlike a fixed debounce delay, deferred rendering is interruptible and adapts to rendering work.
React 18 introduces useSyncExternalStore so libraries that integrate external stores can support concurrent rendering with synchronous external-store updates.
React 18's updated TypeScript definitions no longer implicitly add children to many component prop types. Components that accept children should declare the prop explicitly.
State updates are automatically batched more broadly
Action required
behaviorhigh impact
React 18 automatically batches updates from promises, timeouts, native event handlers, and other asynchronous sources when using the new root API. Code that depends on intermediate synchronous DOM updates may behave differently.
Review code that depends on observing the DOM between state updates. If synchronous DOM flushing is genuinely required, React provides flushSync as an escape hatch.
React 18 adds a development-only StrictMode check that simulates unmounting and remounting newly mounted components while restoring their previous state. Effects must tolerate repeated setup and cleanup.
If a component suspends before a new tree has been fully added, React 18 discards the incomplete tree and retries rendering after the asynchronous work resolves.
Migration
Review components and libraries that relied on effects or DOM from partially committed Suspense trees.
When a Suspense tree re-suspends and returns to a fallback, React 18 cleans up layout effects and recreates them when the content becomes visible again.
Migration
Ensure layout effects correctly clean up subscriptions, observers, or measurements when Suspense hides and later restores content.
React 18 adds a development-only Strict Mode check that simulates unmounting and remounting components when they mount for the first time. Effects must tolerate setup and cleanup running more than once.
Review effects for missing cleanup, non-idempotent setup, duplicated subscriptions, or assumptions that an effect runs only once. The additional behavior is development-only and is intended to surface concurrency-related bugs.
React 18 synchronously flushes effects caused by discrete user events such as clicks. Code should not depend on the older timing behavior of these effects.
With a React 18 root, updates inside promises, timeouts, native event handlers, and other async contexts are batched automatically. This can change when intermediate renders occur.
Beforetsx
fetchData().then(() => {
setCount((count) => count + 1);
setFlag((flag) => !flag);
// React 17:
// two separate renders
});
Review code that intentionally depends on separate renders between state updates. If synchronous DOM visibility is required in a rare case, ReactDOM.flushSync can opt out of batching.