Return values of React lifecycle methods and API callback functions should have valid types

  • REACT_BAD_API_RETURN_VALUE
  • Error
  • Medium
  • react

This rule applies when the return value of a React lifecycle method or callback function is invalid.

If an invalid value is returned from a React lifecycle method or callback function, it may cause a problem when React uses the value. Even when no immediate problem occurs, the value becomes meaningless.

The lifecycle methods and callback functions which cause problem for an invalid return value are listed below with the valid return values:

  1. render(): React element, array, fragment, portal, string, number, boolean, or null
  2. shouldComponentUpdate(): truthy or falsy value except undefined
  3. getInitialState(): Object or null
  4. getDerivedStateFromProps(): any value except undefined
  5. getSnapshotBeforeUpdate(): any value except undefined
  6. The callback function passed as the first argument of React.forwardRef(): React element, array, fragment, portal, string, number, boolean, or null
  7. The callback function passed as the first argument of React.lazy(): dynamic import()
  8. The callback function passed as the first argument of React.useEffect(): undefined or function

In the above cases, since a specific value should be returned, it might be a programmer's mistake returning a wrong value or forgetting a return statement. React throws an error in render() and React.lazy() cases and outputs a warning message in the other cases.

Also, this rule checks the following which need no return value:

  1. componentWillMount()
  2. componentDidMount()
  3. componentWillReceiveProps()
  4. componentWillUpdate()
  5. componentDidUpdate()
  6. componentWillUnmount()
  7. componentDidCatch()
  8. UNSAFE_componentWillMount() (for componentWillMount() deprecation process since v16.3)
  9. UNSAFE_componentWillReceiveProps() (for componentWillReceiveProps() deprecation process since v16.3)
  10. UNSAFE_componentWillUpdate() (for componentWillUpdate() deprecation process since v16.3)
  11. The callback function passed as the second argument of setState()
  12. The callback function passed as the first argument of forceUpdate()

In the above cases, returning a value has no effect.

Noncompliant Code Example

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

export class Example1 extends React.Component {
    render() {
        <div>Hello</div>; // REACT_BAD_API_RETURN_VALUE alarm because 'render()' does not return this React element.
    }
}

export class Example2 extends React.Component {
    render() {
        if (!this.props.myProp) {
            return; // REACT_BAD_API_RETURN_VALUE alarm because null should be returned when rendering nothing.
        }
        return <div>Hello {this.props.myProp}</div>;
    }
}

export class Example3 extends React.Component {
    constructor(props) {
        super(props);
        this.state = { greetName: 'Hi' };
        this.handleClick = this.handleClick.bind(this);
    }
    handleClick() {
        this.setState({ greetName: 'Bye' });
    }
    render() {
        return <div onClick={this.handleClick}>{this.state.greetName}</div>;
    }
    shouldComponentUpdate(nextProps, nextState) {
        if (nextState.greetName === this.state.greetName) {
            return false;
        }
        // REACT_BAD_API_RETURN_VALUE alarm because 'shouldComponentUpdate()' should return a boolean value, but returning 'true' is missing in this path, so 'greetName' will not be updated.
    }
}

Compliant Code Example

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

export class Example1 extends React.Component {
    render() {
        return (
            <div>Hello</div>
        );
    }
}

export class Example2 extends React.Component {
    render() {
        if (!this.props.myProp) {
            return null;
        }
        return <div>Hello {this.props.myProp}</div>;
    }
}

export class Example3 extends React.Component {
    constructor(props) {
        super(props);
        this.state = { greetName: 'Hi' };
        this.handleClick = this.handleClick.bind(this);
    }
    handleClick() {
        this.setState({ greetName: 'Bye' });
    }
    render() {
        return <div onClick={this.handleClick}>{this.state.greetName}</div>;
    }
    shouldComponentUpdate(nextProps, nextState) {
        if (nextState.greetName === this.state.greetName) {
            return false;
        }
        return true;
    }
}

Version

This rule was introduced in DeepScan 1.4.0-beta.

See

  • React.Component methods

  • React Error: A valid React element (or null) must be returned. You may have returned undefined, an array or some other invalid object.

  • React Warning: getSnapshotBeforeUpdate(): A snapshot value (or null) must be returned. You have returned undefined.

  • React Warning: getDerivedStateFromProps(): A valid state object (or null) must be returned. You have returned undefined.

  • React Warning: An effect function must not return anything besides a function, which is used for clean-up.

  • UNSAFE_* lifecycles

Was this documentation helpful?