<p dir="auto">This issue is very similar to <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="623554822" data-permission-text="Title is private" data-url="https://github.com/facebook/react/issues/18985" data-hovercard-type="issue" data-hovercard-url="/facebook/react/issues/18985/hovercard" href="https://github.com/facebook/react/issues/18985">#18985</a> but it happens with <code class="notranslate">useCallback</code> instead of <code class="notranslate">useEffect</code>, and the error message is different.</p>
<p dir="auto">eslint-plugin-react-hooks version: 4.0.4</p>
<h2 dir="auto">Steps To Reproduce</h2>
<p dir="auto">The order of reference matters, if you flip the two calls to <code class="notranslate">console.log</code> no error is reported. And as in <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="623554822" data-permission-text="Title is private" data-url="https://github.com/facebook/react/issues/18985" data-hovercard-type="issue" data-hovercard-url="/facebook/react/issues/18985/hovercard" href="https://github.com/facebook/react/issues/18985">#18985</a> replacing <code class="notranslate">?.</code> with <code class="notranslate">.</code> won't result in an error.</p>
<div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="function MyComponent(props) {
  useCallback(() =&gt; {
    console.log(props?.foo);
    console.log(props);
  }, [props]);
};"><pre class="notranslate"><span class="pl-k">function</span> <span class="pl-v">MyComponent</span><span class="pl-kos">(</span><span class="pl-s1">props</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
  <span class="pl-en">useCallback</span><span class="pl-kos">(</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span> <span class="pl-kos">{</span>
    <span class="pl-smi">console</span><span class="pl-kos">.</span><span class="pl-en">log</span><span class="pl-kos">(</span><span class="pl-s1">props</span><span class="pl-kos">?.</span><span class="pl-c1">foo</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
    <span class="pl-smi">console</span><span class="pl-kos">.</span><span class="pl-en">log</span><span class="pl-kos">(</span><span class="pl-s1">props</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
  <span class="pl-kos">}</span><span class="pl-kos">,</span> <span class="pl-kos">[</span><span class="pl-s1">props</span><span class="pl-kos">]</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span><span class="pl-kos">;</span></pre></div>
<details>
<summary>package.json</summary>
<div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="{
  &quot;name&quot;: &quot;bug-react-hooks&quot;,
  &quot;version&quot;: &quot;1.0.0&quot;,
  &quot;description&quot;: &quot;&quot;,
  &quot;license&quot;: &quot;ISC&quot;,
  &quot;scripts&quot;: {
    &quot;test&quot;: &quot;eslint test.js&quot;
  },
  &quot;dependencies&quot;: {
    &quot;babel-eslint&quot;: &quot;^10.1.0&quot;,
    &quot;eslint&quot;: &quot;^7.1.0&quot;,
    &quot;eslint-plugin-react-hooks&quot;: &quot;^4.0.4&quot;
  },
  &quot;eslintConfig&quot;: {
    &quot;parser&quot;: &quot;babel-eslint&quot;,
    &quot;parserOptions&quot;: {
      &quot;sourceType&quot;: &quot;module&quot;
    },
    &quot;plugins&quot;: [
      &quot;react-hooks&quot;
    ],
    &quot;rules&quot;: {
      &quot;react-hooks/exhaustive-deps&quot;: &quot;warn&quot;
    }
  }
}"><pre class="notranslate"><span class="pl-kos">{</span>
  <span class="pl-s">"name"</span>: <span class="pl-s">"bug-react-hooks"</span><span class="pl-kos">,</span>
  <span class="pl-s">"version"</span>: <span class="pl-s">"1.0.0"</span><span class="pl-kos">,</span>
  <span class="pl-s">"description"</span>: <span class="pl-s">""</span><span class="pl-kos">,</span>
  <span class="pl-s">"license"</span>: <span class="pl-s">"ISC"</span><span class="pl-kos">,</span>
  <span class="pl-s">"scripts"</span>: <span class="pl-kos">{</span>
    <span class="pl-s">"test"</span>: <span class="pl-s">"eslint test.js"</span>
  <span class="pl-kos">}</span><span class="pl-kos">,</span>
  <span class="pl-s">"dependencies"</span>: <span class="pl-kos">{</span>
    <span class="pl-s">"babel-eslint"</span>: <span class="pl-s">"^10.1.0"</span><span class="pl-kos">,</span>
    <span class="pl-s">"eslint"</span>: <span class="pl-s">"^7.1.0"</span><span class="pl-kos">,</span>
    <span class="pl-s">"eslint-plugin-react-hooks"</span>: <span class="pl-s">"^4.0.4"</span>
  <span class="pl-kos">}</span><span class="pl-kos">,</span>
  <span class="pl-s">"eslintConfig"</span>: <span class="pl-kos">{</span>
    <span class="pl-s">"parser"</span>: <span class="pl-s">"babel-eslint"</span><span class="pl-kos">,</span>
    <span class="pl-s">"parserOptions"</span>: <span class="pl-kos">{</span>
      <span class="pl-s">"sourceType"</span>: <span class="pl-s">"module"</span>
    <span class="pl-kos">}</span><span class="pl-kos">,</span>
    <span class="pl-s">"plugins"</span>: <span class="pl-kos">[</span>
      <span class="pl-s">"react-hooks"</span>
    <span class="pl-kos">]</span><span class="pl-kos">,</span>
    <span class="pl-s">"rules"</span>: <span class="pl-kos">{</span>
      <span class="pl-s">"react-hooks/exhaustive-deps"</span>: <span class="pl-s">"warn"</span>
    <span class="pl-kos">}</span>
  <span class="pl-kos">}</span>
<span class="pl-kos">}</span></pre></div>
</details>
<h2 dir="auto">The current behavior</h2>
<p dir="auto">The following warning is reported:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="5:6  warning  React Hook useCallback has an unnecessary dependency: 'props'. Either exclude it or remove the dependency array  react-hooks/exhaustive-deps"><pre lang="text" class="notranslate"><code class="notranslate">5:6  warning  React Hook useCallback has an unnecessary dependency: 'props'. Either exclude it or remove the dependency array  react-hooks/exhaustive-deps
</code></pre></div>
<h2 dir="auto">The expected behavior</h2>
<p dir="auto">No warning should be reported.</p>
<p dir="auto">This is, I believe, an extension of the issue reported in <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="623554822" data-permission-text="Title is private" data-url="https://github.com/facebook/react/issues/18985" data-hovercard-type="issue" data-hovercard-url="/facebook/react/issues/18985/hovercard" href="https://github.com/facebook/react/issues/18985">#18985</a>.</p>
<p dir="auto">While the PR that resolved that issue fixed the lint rule for the <code class="notranslate">useEffect</code> hook, it seems to remain an issue for <code class="notranslate">useCallback</code> and <code class="notranslate">useMemo</code>.</p>
<p dir="auto">When the optional chaining operator (<code class="notranslate">?.</code>) is used to access a path inside a <code class="notranslate">useMemo</code> or <code class="notranslate">useCallback</code> hook, and a prefix of that path is listed in the dependencies array, eslint-plugin-react-hooks reports an unexpected "missing dependency" warning. Replacing <code class="notranslate">?.</code> with <code class="notranslate">. </code> produces the expected behaviour: the warning is no longer reported.</p>
<p dir="auto">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.)</p>
<p dir="auto">React version: 16.13.1<br>
eslint-plugin-react-hooks version: 4.0.4</p>
<h2 dir="auto">Steps To Reproduce</h2>

<div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content=" import React, {useEffect} from 'react';

 export function MyComponent(props) {
   useCallback(() =&gt; {
     console.log(props.foo?.toString());
   }, [props.foo]);
    
    return null;
  }"><pre class="notranslate"> <span class="pl-k">import</span> <span class="pl-v">React</span><span class="pl-kos">,</span> <span class="pl-kos">{</span><span class="pl-s1">useEffect</span><span class="pl-kos">}</span> <span class="pl-k">from</span> <span class="pl-s">'react'</span><span class="pl-kos">;</span>

 <span class="pl-k">export</span> <span class="pl-k">function</span> <span class="pl-v">MyComponent</span><span class="pl-kos">(</span><span class="pl-s1">props</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
   <span class="pl-en">useCallback</span><span class="pl-kos">(</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span> <span class="pl-kos">{</span>
     <span class="pl-smi">console</span><span class="pl-kos">.</span><span class="pl-en">log</span><span class="pl-kos">(</span><span class="pl-s1">props</span><span class="pl-kos">.</span><span class="pl-c1">foo</span><span class="pl-kos">?.</span><span class="pl-en">toString</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
   <span class="pl-kos">}</span><span class="pl-kos">,</span> <span class="pl-kos">[</span><span class="pl-s1">props</span><span class="pl-kos">.</span><span class="pl-c1">foo</span><span class="pl-kos">]</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
    
    <span class="pl-k">return</span> <span class="pl-c1">null</span><span class="pl-kos">;</span>
  <span class="pl-kos">}</span></pre></div>
<ul dir="auto">
<li>It doesn't matter what <code class="notranslate">foo</code>, represents, other than it has a prototype method, <code class="notranslate">toString()</code>.</li>
<li>We don't want to reference the prototype method of <code class="notranslate">foo</code> (<code class="notranslate">props.foo?.toString</code>) in the dependencies array because our function depends on <code class="notranslate">props.foo</code>, not the prototype of <code class="notranslate">props.foo</code>.</li>
</ul>

<h2 dir="auto">The current behavior</h2>
<p dir="auto">The following warning is reported:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="React Hook useCallback has an unnecessary dependency: 'props.foo'. Either exclude it or remove the dependency array  react-hooks/exhaustive-deps"><pre class="notranslate"><code class="notranslate">React Hook useCallback has an unnecessary dependency: 'props.foo'. Either exclude it or remove the dependency array  react-hooks/exhaustive-deps
</code></pre></div>
<ul dir="auto">
<li>Note that if I list <code class="notranslate">props.foo?.toString</code> instead of <code class="notranslate">props.foo</code> in the dependencies, no warning is reported. However, this is not acceptable as the callback depends on <code class="notranslate">props.foo</code>, not the prototype of <code class="notranslate">props.foo</code>.</li>
<li>If I remove the optional chaining operator from the above code (so that the body of the callback reads <code class="notranslate">console.log(props.foo?.toString());</code>) then no warning is reported, as expected.</li>
</ul>
<h2 dir="auto">The expected behavior</h2>
<p dir="auto">No warning should be reported.</p>