81 lines
3.4 KiB
Plaintext
81 lines
3.4 KiB
Plaintext
![]() |
== Why is this an issue?
|
||
|
|
||
|
React works in two phases: render and commit.
|
||
|
|
||
|
* The render phase determines what changes need to be made to e.g. the DOM. During this phase, React calls render and then compares the result to the previous render.
|
||
|
* The commit phase is when React applies any changes. (In the case of React DOM, this is when React inserts, updates, and removes DOM nodes.) React also calls lifecycles like `componentDidMount` and `componentDidUpdate` during this phase.
|
||
|
|
||
|
Render phase lifecycles include among others, the following lifecycle methods:
|
||
|
|
||
|
* `componentWillMount` (or its alias `UNSAFE_componentWillMount`)
|
||
|
* `componentWillReceiveProps` (or its alias `UNSAFE_componentWillReceiveProps`)
|
||
|
* `componentWillUpdate` (or its alias `UNSAFE_componentWillUpdate`)
|
||
|
|
||
|
These are considered unsafe and also happen to be the lifecycles that cause the most confusion within the React community and tend to encourage unsafe coding practices.
|
||
|
|
||
|
[source,javascript]
|
||
|
----
|
||
|
class Foo extends React.Component {
|
||
|
UNSAFE_componentWillMount() {} // Noncompliant
|
||
|
UNSAFE_componentWillReceiveProps() {} // Noncompliant
|
||
|
UNSAFE_componentWillUpdate() {} // Noncompliant
|
||
|
}
|
||
|
----
|
||
|
|
||
|
|
||
|
== How to fix it
|
||
|
|
||
|
Instead of `componentWillUpdate`, use `getSnapshotBeforeUpdate` together with `componentDidUpdate`. The `getSnapshotBeforeUpdate` lifecycle is called right before mutations are made. The return value for this lifecycle will be passed as the third parameter to `componentDidUpdate`.
|
||
|
|
||
|
Instead of `componentWillReceiveProps`, Use `getDerivedStateFromProps` together with `componentDidUpdate`. The `getDerivedStateFromProps` lifecycle is invoked after a component is instantiated as well as before it is re-rendered. It can return an object to update state, or null to indicate that the new props do not require any state updates.
|
||
|
|
||
|
As for `componentWillMount`, React will call it immediately after the constructor. It only exists for historical reasons and should not be used. Instead, use one of the alternatives:
|
||
|
|
||
|
* To initialize state, declare `state` as a class field or set `this.state` inside the `constructor`.
|
||
|
* If you need to run a side effect or set up a subscription, move that logic to `componentDidMount` instead.
|
||
|
|
||
|
=== Code examples
|
||
|
|
||
|
==== Noncompliant code example
|
||
|
|
||
|
[source,javascript,diff-id=2,diff-type=noncompliant]
|
||
|
----
|
||
|
class myComponent extends React.Component {
|
||
|
constructor(props) {
|
||
|
super(props);
|
||
|
}
|
||
|
|
||
|
componentWillMount() { // Noncompliant: "componentWillMount" is deprecated
|
||
|
if (localStorage.getItem("token")) {
|
||
|
this.setState({logged_in: true});
|
||
|
}
|
||
|
}
|
||
|
// ...
|
||
|
}
|
||
|
----
|
||
|
|
||
|
==== Compliant solution
|
||
|
|
||
|
[source,javascript,diff-id=2,diff-type=compliant]
|
||
|
----
|
||
|
class myComponent extends React.Component {
|
||
|
constructor(props) {
|
||
|
super(props);
|
||
|
|
||
|
if (localStorage.getItem("token")) {
|
||
|
this.setState({logged_in: true});
|
||
|
}
|
||
|
}
|
||
|
// ...
|
||
|
}
|
||
|
----
|
||
|
|
||
|
|
||
|
|
||
|
== Resources
|
||
|
=== Documentation
|
||
|
|
||
|
* https://react.dev/reference/react/Component#unsafe_componentwillmount[React - `UNSAFE_componentWillMount`]
|
||
|
* https://react.dev/reference/react/Component#unsafe_componentwillreceiveprops[React - `UNSAFE_componentWillReceiveProps`]
|
||
|
* https://react.dev/reference/react/Component#unsafe_componentwillupdate[React - `UNSAFE_componentWillUpdate`]
|
||
|
* https://legacy.reactjs.org/blog/2018/03/27/update-on-async-rendering.html#migrating-from-legacy-lifecycles[React - Migrating from Legacy Lifecycles]
|