Unsafe legacy lifecycle methods should not be defined together with newly added replacements

  • REACT_UNINVOKED_UNSAFE_LIFECYCLE
  • Error
  • Medium
  • react

This rule applies when unsafe legacy lifecycle methods are defined together with newly added replacements.

In React v16.3, componentWillMount(), componentWillReceiveProps(), and componentWillUpdate() are marked as unsafe legacy lifecycle methods for deprecation process.
They have often been misused and may cause more problems with the upcoming async rendering.
As safer alternatives for those methods, getSnapshotBeforeUpdate() and getDerivedStateFromProps() were newly added.

Since the roles of the unsafe methods and the newly added methods may overlap, React prevents the unsafe methods from being called when the alternatives are defined and outputs a warning message.

The full list of the unsafe legacy lifecycle methods is as follows:

  1. componentWillMount()
  2. UNSAFE_componentWillMount()
  3. componentWillReceiveProps()
  4. UNSAFE_componentWillReceiveProps()
  5. componentWillUpdate()
  6. UNSAFE_componentWillUpdate()

Noncompliant Code Example

View with compliant examples side by side
import React from 'react';

class Hello extends React.Component {
    constructor(props) {
        super(props);
        this.state = { msg: 'hi' };
        this.handleClick = this.handleClick.bind(this);
        this.helloRef = React.createRef();
    }
    getSnapshotBeforeUpdate(prevProps, prevState) {
        if (prevState.msg !== this.state.msg) {
            const hello = this.helloRef.current;
            return hello.offsetLeft;
        }
        return null;
    }
    componentDidUpdate(prevProps, prevState, snapshot) {
        if (snapshot !== null) {
            this.helloRef.current.style.left = (snapshot + 10) + "px";
        }
    }
    componentWillUpdate(nextProps, nextState) { // REACT_UNINVOKED_UNSAFE_LIFECYCLE alarm because 'getSnapshotBeforeUpdate()' is defined.
        this.curOffsetLeft = this.helloRef.current.offsetLeft;
    }
    handleClick() {
        if (this.state.msg === 'hi') {
            this.setState({ msg: 'bye' });
        } else {
            this.setState({ msg: 'hi' });
        }
    }
    render() {
        return <div ref={this.helloRef} onClick={this.handleClick} style={{ position: "absolute" }}>{this.state.msg}</div>;
    }
}

Compliant Code Example

View with noncompliant examples side by side
import React from 'react';

class Hello extends React.Component {
    constructor(props) {
        super(props);
        this.state = { msg: 'hi' };
        this.handleClick = this.handleClick.bind(this);
        this.helloRef = React.createRef();
    }
    getSnapshotBeforeUpdate(prevProps, prevState) {
        if (prevState.msg !== this.state.msg) {
            const hello = this.helloRef.current;
            return hello.offsetLeft;
        }
        return null;
    }
    componentDidUpdate(prevProps, prevState, snapshot) {
        if (snapshot !== null) {
            this.helloRef.current.style.left = (snapshot + 10) + "px";
        }
    }
    handleClick() {
        if (this.state.msg === 'hi') {
            this.setState({ msg: 'bye' });
        } else {
            this.setState({ msg: 'hi' });
        }
    }
    render() {
        return <div ref={this.helloRef} onClick={this.handleClick} style={{ position: "absolute" }}>{this.state.msg}</div>;
    }
}

Version

This rule was introduced in DeepScan 1.13.0-beta.

See

  • Lifecycle Changes

  • React Warning: Unsafe legacy lifecycles will not be called for components using new component APIs. Hello uses getSnapshotBeforeUpdate() but also contains the following legacy lifecycles: componentWillMount. The above lifecycles should be removed. Learn more about this warning here: https://fb.me/react-async-component-lifecycle-hooks