Skip to main content

How did React 18 change the lifecycle?

1. The main idea of React 18 - Concurrent Rendering

Before React 18:

  • React rendered a component synchronously: once rendering started, it ran to completion - it couldn't be paused, cancelled, or merged with other updates.
  • All lifecycles were called in a strictly predictable order (mount -> commit -> effects).

With React 18:

  • Rendering became asynchronous and interruptible (via Fiber concurrent mode).
  • React can now:
    • pause rendering,
    • roll back incomplete changes,
    • re-run effects,
    • merge several state updates into one "session".

This directly affects calls to the lifecycle and hooks, since effects can now run more than once in dev mode, and "mounting" can be simulated multiple times.


2. Behavior in Strict Mode (React 18)

The change most noticeable to developers:

React 18 now calls useEffect, useLayoutEffect, componentDidMount, componentWillUnmount twice (in DEV mode), to help find "impure effects".

This is called "Strict Mode double invocation" and happens only in dev, to verify that your effects and cleanups (cleanup) are deterministic and don't depend on call order.

Example:

javascript
useEffect(() => { console.log('effect'); return () => console.log('cleanup'); }, []);

In React 18 (in StrictMode) you will see:

javascript
effect cleanup effect

Why: React simulates unmounting and remounting to verify that your effect correctly cleans up its resources (timers, listeners, subscriptions).

This isn't a bug, it's part of the new "concurrent safety check".


3. Changes to lifecycle phases under the hood

The lifecycle is now understood within two Fiber phases:

PhasePurposeMethods/hooks
Render PhaseReact computes what needs to be updated (can be paused)render(), useMemo, useCallback, shouldComponentUpdate
Commit PhaseReact applies changes to the DOM (always synchronous)componentDidMount, componentDidUpdate, useLayoutEffect, useEffect

In React 18 the Render Phase can:

  • run multiple times (React can "prepare" different versions of the UI and then choose one);
  • not reach commit, if the render is cancelled;
  • run in the background (background rendering).

4. What specifically changed in lifecycle behavior

componentWillMount, componentWillUpdate, componentWillReceiveProps

Officially deprecated even earlier (React 16) and fully incompatible with concurrent mode - React 18 doesn't call them at all in concurrent rendering. Their safe replacements are:

  • getDerivedStateFromProps
  • getSnapshotBeforeUpdate
  • componentDidUpdate

componentDidMount / useEffect / useLayoutEffect

  • Still called in the commit phase, but React can call cleanup -> effect again when switching between renders of different priority.
  • In dev mode (StrictMode) they run twice on mount (see above).
  • In concurrent mode React can cancel a render before commit, and in that case the effects won't be called at all (since the DOM didn't change).

componentDidUpdate

  • Called only for components that were actually committed. If the render is cancelled (for example, on a transition to a new state), the method isn't called.

componentWillUnmount / cleanup in useEffect

  • Now React guarantees it calls cleanup:
    • on unmount,
    • before a new effect,
    • on a cancelled render (in some dev-mode cases).
  • This makes effect logic more predictable and safe.

shouldComponentUpdate

  • Its behavior hasn't changed directly, but React can now interrupt or defer rendering, so the check may run several times before commit.

5. New React 18 features affecting the "lifecycle"

New featureWhat it doesHow it affects things
Concurrent RenderingAsynchronous, priority-based renderingMethods can be called more than once, effects can be deferred
Automatic BatchingReact now groups all state updates, even inside promisesFewer "extra" re-renders, different useEffect behavior
Transitions (startTransition)Lets you separate "urgent" and "non-urgent" updatesThe lifecycle of low-priority updates can be called later
useId, useSyncExternalStore, useInsertionEffectNew hooks for correct behavior in concurrent modeOptimize access to the DOM, styles, and external data

6. What changed for useEffect

BehaviorReact 17React 18
The effect runs once in devYesNo - twice (Strict Mode)
Cleanup runs only on unmountYesNo - also before the effect runs again
The effect can be deferredNoYes (due to concurrent rendering)
A "cancelled" effect is possible (if commit didn't happen)NoYes

7. The main thing to remember

  • React 18 doesn't "break" the lifecycle, it makes it more precise, asynchronous, and safe.
  • In production, effects are still called once - "twice" only happens in dev.
  • It's important to write pure effects - with no side effects in the component body and no dependency on the number of calls.

Short summary table

What changedReact < 18React 18
RenderingSynchronousAsynchronous / priority-based
LifecycleSingle-passCan be paused / repeated
Effects (useEffect)Single callDouble call in StrictMode (dev)
Cleanup (cleanup)Only on unmountAlso on remounting
Old methods (componentWill*)Work (legacy mode)Incompatible
State batchingOnly inside eventsAutomatic everywhere
New hooks-useId, useSyncExternalStore, useInsertionEffect

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.