Suggest an editImprove this articleRefine the answer for “How did React 18 change the lifecycle?”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)The main idea of React 18 is **Concurrent Rendering**: rendering became asynchronous and interruptible (via Fiber concurrent mode), and React can now pause rendering, roll back incomplete changes, re-run effects, and merge several state updates into one "session". **Key point:** in production, effects still run once - the "double" run only happens in dev mode (Strict Mode), to verify that effects and cleanup are deterministic.Shown above the full answer for quick recall.Answer (EN)Image## 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:** | Phase | Purpose | Methods/hooks | |---|---|---| | **Render Phase** | React computes what needs to be updated (can be paused) | `render()`, `useMemo`, `useCallback`, `shouldComponentUpdate` | | **Commit Phase** | React 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 feature | What it does | How it affects things | |---|---|---| | **Concurrent Rendering** | Asynchronous, priority-based rendering | Methods can be called more than once, effects can be deferred | | **Automatic Batching** | React now groups all state updates, even inside promises | Fewer "extra" re-renders, different `useEffect` behavior | | **Transitions (**`startTransition`**)** | Lets you separate "urgent" and "non-urgent" updates | The lifecycle of low-priority updates can be called later | | **useId, useSyncExternalStore, useInsertionEffect** | New hooks for correct behavior in concurrent mode | Optimize access to the DOM, styles, and external data | --- ## 6. What changed for `useEffect` | Behavior | React 17 | React 18 | |---|---|---| | The effect runs once in dev | Yes | No - twice (Strict Mode) | | Cleanup runs only on unmount | Yes | No - also before the effect runs again | | The effect can be deferred | No | Yes (due to concurrent rendering) | | A "cancelled" effect is possible (if commit didn't happen) | No | Yes | --- ## 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 changed | React < 18 | React 18 | |---|---|---| | Rendering | Synchronous | Asynchronous / priority-based | | Lifecycle | Single-pass | Can be paused / repeated | | Effects (`useEffect`) | Single call | Double call in StrictMode (dev) | | Cleanup (`cleanup`) | Only on unmount | Also on remounting | | Old methods (`componentWill*`) | Work (legacy mode) | Incompatible | | State batching | Only inside events | Automatic everywhere | | New hooks | - | `useId`, `useSyncExternalStore`, `useInsertionEffect` |For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.