React 18 lifecycle patterns
Classify the semantics of unsafe class lifecycle methods before changing code, then apply the matching React 18.3.1 migration pattern from the bundled references.
When to invoke
- "Migrate
componentWillMount in this component."
- "Fix React 18 UNSAFE lifecycle warnings."
- "Should this use
getDerivedStateFromProps or componentDidUpdate?"
- "Add
getSnapshotBeforeUpdate for scroll position."
- "Replace
componentWillReceiveProps safely."
Procedure
- Identify which unsafe lifecycle appears:
componentWillMount, componentWillReceiveProps, or componentWillUpdate.
- Classify what the method does semantically before editing.
- Read the matching bundled reference file and case section.
- Apply the before/after pattern exactly enough to preserve behavior.
- Avoid permanent
UNSAFE_ prefixes; if a temporary prefix is unavoidable, add the required TODO.
- Validate behavior with existing React tests or targeted component checks.
Quick decision guide
componentWillMount
| What it does |
Correct migration |
Reference |
Sets initial state with this.setState(...) |
Move to constructor. |
references/componentWillMount.md#case-a |
| Runs a side effect such as fetch, subscription, or DOM access |
Move to componentDidMount. |
references/componentWillMount.md#case-b |
| Derives initial state from props |
Move to constructor with props. |
references/componentWillMount.md#case-c |
componentWillReceiveProps
| What it does |
Correct migration |
Reference |
| Async side effect triggered by prop change, such as fetch or cancel |
Use componentDidUpdate with previous-prop comparison. |
references/componentWillReceiveProps.md#case-a |
| Pure state derivation from new props with no side effects |
Use getDerivedStateFromProps. |
references/componentWillReceiveProps.md#case-b |
componentWillUpdate
| What it does |
Correct migration |
Reference |
| Reads DOM state before update, such as scroll, size, or position |
Use getSnapshotBeforeUpdate and consume the snapshot in componentDidUpdate. |
references/componentWillUpdate.md#case-a |
| Cancels requests or runs effects before update |
Use componentDidUpdate with previous-value comparison. |
references/componentWillUpdate.md#case-b |
UNSAFE prefix rule
Never use UNSAFE_componentWillMount, UNSAFE_componentWillReceiveProps, or UNSAFE_componentWillUpdate as a permanent fix. Prefixing suppresses React 18.3.1 warnings but does not fix concurrent mode safety issues, does not prepare for React 19 removal, and does not address the semantic migration.
If a temporary prefix is explicitly chosen as a stopgap, mark it with this exact intent:
// TODO: React 19 will remove this. Migrate before React 19 upgrade.
// UNSAFE_ prefix added temporarily - replace with componentDidMount / getDerivedStateFromProps / etc.
Progressive disclosure and bundled resources
references/componentWillMount.md: three cases for initial state, side effects, and props-derived initial state.
references/componentWillReceiveProps.md: componentDidUpdate versus getDerivedStateFromProps, including trap warnings.
references/componentWillUpdate.md: getSnapshotBeforeUpdate plus componentDidUpdate pairing.
Gotchas
- Wrong category means wrong migration: a side effect in
componentWillReceiveProps belongs in componentDidUpdate, not getDerivedStateFromProps.
getSnapshotBeforeUpdate is paired: DOM snapshots are returned before commit and consumed in componentDidUpdate.
UNSAFE_ is not a migration: treat it only as a temporary scheduling marker.
Output template
## React lifecycle migration
**Status:** complete | needs changes | blocked
**Component:** `<component name or path>`
**Original lifecycle:** `componentWillMount` | `componentWillReceiveProps` | `componentWillUpdate`
**Migration pattern:** `constructor` | `componentDidMount` | `componentDidUpdate` | `getDerivedStateFromProps` | `getSnapshotBeforeUpdate`
| Behavior found | Pattern applied | Reference | Validation |
| --- | --- | --- | --- |
| <state, side effect, DOM read, or cancel> | <new lifecycle/API> | `references/<file>.md#case-x` | <test/check> |
Quality gate
1---2name: react18-lifecycle-patterns-23description: Migrate unsafe React class component lifecycle methods to React 18.3.1-safe patterns. Use when fixing `componentWillMount`, `componentWillReceiveProps`, `componentWillUpdate`, `UNSAFE_` lifecycle warnings, choosing `getDerivedStateFromProps` versus `componentDidUpdate`, or adding `getSnapshotBeforeUpdate`.4---56# React 18 lifecycle patterns78Classify the semantics of unsafe class lifecycle methods before changing code, then apply the matching React 18.3.1 migration pattern from the bundled references.910## When to invoke1112- "Migrate `componentWillMount` in this component."13- "Fix React 18 UNSAFE lifecycle warnings."14- "Should this use `getDerivedStateFromProps` or `componentDidUpdate`?"15- "Add `getSnapshotBeforeUpdate` for scroll position."16- "Replace `componentWillReceiveProps` safely."1718## Procedure19201. Identify which unsafe lifecycle appears: `componentWillMount`, `componentWillReceiveProps`, or `componentWillUpdate`.212. Classify what the method does semantically before editing.223. Read the matching bundled reference file and case section.234. Apply the before/after pattern exactly enough to preserve behavior.245. Avoid permanent `UNSAFE_` prefixes; if a temporary prefix is unavoidable, add the required TODO.256. Validate behavior with existing React tests or targeted component checks.2627## Quick decision guide2829### componentWillMount3031| What it does | Correct migration | Reference |32| --- | --- | --- |33| Sets initial state with `this.setState(...)` | Move to `constructor`. | `references/componentWillMount.md#case-a` |34| Runs a side effect such as fetch, subscription, or DOM access | Move to `componentDidMount`. | `references/componentWillMount.md#case-b` |35| Derives initial state from props | Move to `constructor` with props. | `references/componentWillMount.md#case-c` |3637### componentWillReceiveProps3839| What it does | Correct migration | Reference |40| --- | --- | --- |41| Async side effect triggered by prop change, such as fetch or cancel | Use `componentDidUpdate` with previous-prop comparison. | `references/componentWillReceiveProps.md#case-a` |42| Pure state derivation from new props with no side effects | Use `getDerivedStateFromProps`. | `references/componentWillReceiveProps.md#case-b` |4344### componentWillUpdate4546| What it does | Correct migration | Reference |47| --- | --- | --- |48| Reads DOM state before update, such as scroll, size, or position | Use `getSnapshotBeforeUpdate` and consume the snapshot in `componentDidUpdate`. | `references/componentWillUpdate.md#case-a` |49| Cancels requests or runs effects before update | Use `componentDidUpdate` with previous-value comparison. | `references/componentWillUpdate.md#case-b` |5051## UNSAFE prefix rule5253Never use `UNSAFE_componentWillMount`, `UNSAFE_componentWillReceiveProps`, or `UNSAFE_componentWillUpdate` as a permanent fix. Prefixing suppresses React 18.3.1 warnings but does not fix concurrent mode safety issues, does not prepare for React 19 removal, and does not address the semantic migration.5455If a temporary prefix is explicitly chosen as a stopgap, mark it with this exact intent:5657```jsx58// TODO: React 19 will remove this. Migrate before React 19 upgrade.59// UNSAFE_ prefix added temporarily - replace with componentDidMount / getDerivedStateFromProps / etc.60```6162## Progressive disclosure and bundled resources6364- `references/componentWillMount.md`: three cases for initial state, side effects, and props-derived initial state.65- `references/componentWillReceiveProps.md`: `componentDidUpdate` versus `getDerivedStateFromProps`, including trap warnings.66- `references/componentWillUpdate.md`: `getSnapshotBeforeUpdate` plus `componentDidUpdate` pairing.6768## Gotchas6970- **Wrong category means wrong migration**: a side effect in `componentWillReceiveProps` belongs in `componentDidUpdate`, not `getDerivedStateFromProps`.71- **`getSnapshotBeforeUpdate` is paired**: DOM snapshots are returned before commit and consumed in `componentDidUpdate`.72- **`UNSAFE_` is not a migration**: treat it only as a temporary scheduling marker.7374## Output template7576```markdown77## React lifecycle migration7879**Status:** complete | needs changes | blocked80**Component:** `<component name or path>`81**Original lifecycle:** `componentWillMount` | `componentWillReceiveProps` | `componentWillUpdate`82**Migration pattern:** `constructor` | `componentDidMount` | `componentDidUpdate` | `getDerivedStateFromProps` | `getSnapshotBeforeUpdate`8384| Behavior found | Pattern applied | Reference | Validation |85| --- | --- | --- | --- |86| <state, side effect, DOM read, or cancel> | <new lifecycle/API> | `references/<file>.md#case-x` | <test/check> |87```8889## Quality gate9091- [ ] The original lifecycle method and semantic category were identified before editing.92- [ ] The matching bundled reference file was consulted.93- [ ] `componentWillMount`, `componentWillReceiveProps`, and `componentWillUpdate` are removed or explicitly justified as temporary `UNSAFE_` stopgaps.94- [ ] `getDerivedStateFromProps` is used only for pure state derivation from props.95- [ ] DOM reads before update use `getSnapshotBeforeUpdate` with `componentDidUpdate`.96- [ ] Existing tests or targeted checks validate preserved behavior.