Skip to content

Bug: react-hooks/exhaustive-deps not recognizing dependencies when accessed via optional chaining #19061

@fredvollmer

Description

@fredvollmer

This is, I believe, an extension of the issue reported in #18985.

While the PR that resolved that issue fixed the lint rule for the useEffect hook, it seems to remain an issue for useCallback and useMemo.

When the optional chaining operator (?.) is used to access a path inside a useMemo or useCallback hook, and a prefix of that path is listed in the dependencies array, eslint-plugin-react-hooks reports an unexpected "missing dependency" warning. Replacing ?. with . produces the expected behaviour: the warning is no longer reported.

In many cases, adding the complete path, rather than a prefix, to the dependencies array is the correct answer. However, in some cases, the complete path might point to a prototype method of an object, in which case only a prefix of the path should be listed. (Hopefully the example below makes this more clear.)

React version: 16.13.1
eslint-plugin-react-hooks version: 4.0.4

Steps To Reproduce

 import React, {useEffect} from 'react';

 export function MyComponent(props) {
   useCallback(() => {
     console.log(props.foo?.toString());
   }, [props.foo]);
    
    return null;
  }
  • It doesn't matter what foo, represents, other than it has a prototype method, toString().
  • We don't want to reference the prototype method of foo (props.foo?.toString) in the dependencies array because our function depends on props.foo, not the prototype of props.foo.

The current behavior

The following warning is reported:

React Hook useCallback has an unnecessary dependency: 'props.foo'. Either exclude it or remove the dependency array  react-hooks/exhaustive-deps
  • Note that if I list props.foo?.toString instead of props.foo in the dependencies, no warning is reported. However, this is not acceptable as the callback depends on props.foo, not the prototype of props.foo.
  • If I remove the optional chaining operator from the above code (so that the body of the callback reads console.log(props.foo?.toString());) then no warning is reported, as expected.

The expected behavior

No warning should be reported.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions