Issue 1:
Context

After reading #14920 (not 100% of it, I admit), I decided to refactor my codebase in order to be more resilient against potential mistakes.

During this conversion, I converted a ton of callbacks to useCallback and made extensive use of the array dependencies for useCallback and useEffect everywhere.

However, I often stumbled upon the following pattern:

const myCallback = useCallback(() => {
// Do something with value.
}, [value]);

const myOtherCallback = useCallback(() => {
const result = myCallback();

// Do something with BOTH value and result.
}, [value, myCallback ]);

useEffect(() => {
// Do something with myCallback, myOtherCallback and value, independently.
}, [value, myCallback, myOtherCallback ])

Basic CodeSandBox with this example

For the sake of argument, let's say that this code can't "move" callbacks around: I can't declare myCallback and/or myOtherCallback because they are used below in the main scope.

Problem

With the above example, we can conclude the following statements:

myCallback will change if value changes

myOtherCallback will change if value or myCallback changes

The useEffect will rerun if myCallback, value or myOtherCallback changes

We can instantly notice there is a lot of redundancy right there:

If value changes, myCallback will change so I only need to specify myCallback as a dependency for myOtherCallback even though I also use value directly.

The same reasoning can be applied to the dependencies of useEffect.

As a human, I could omit value from the dependencies of myOtherCallback and be 100% absolutely guaranteed that the behavior would be strictly identical as per the hooks very own specifications.

But if I do so, the react-hooks/exhaustive-deps eslint rule will complain that I'm missing some dependencies from the array.

Proposal

If I understood properly, the rule does some kind of dependency traversal in order to attempt to recognize infinite loops.

I think it would be nice for it to also be able to detect this kind of dependency redundancies.

Even better, it should be able to take it into account when suggesting changes/reporting errors.

Benefits

From reading the issue I mentionned at the top of this post, there is a fair amout of people who are not happy with the clutter the rule forces us to have in the codebase.

Myself, I'm fairly hesitant and sometimes find myself thinking "I shouldn't need to specify this dep".

Implementing the proposal mentionned above would be extremely beneficial regarding the readability of the code by totally preventing redundancy of dependencies.

Drawbacks

I can see two potential issues with this proposal:

Performance impact

Requiring the rule to recursively assess dependencies may have a performance impact on the linting.

I'm not sure if this is the case since the rule does a similar check to try to avoid infinite loop. (Maybe I'm wrong and it's not the same thing).

If this is too much of an impact, I think it could be opt-in behind a config flag.

This would allow people to decide for themselves if the impact is worth it.

Less obvious dependencies

Not explicitely specifying every used dependency may make it harder to assess the real update impact.

From the above example, I know that my useEffect depends on value. If it weren't there, I would have to mentally climb up the dependencies myself.

I think this is a fake drawback since I always need to climb up the dependencies tree to REALLY know what could cause my effect (or other) to be triggered.

I would even argue that this proposal makes this mental parsing easier because I don't have any redundancy when reading the dependencies: every variable I see in a dependency array is specified exactly once. (Well, there may be exceptions when it comes to diverging dependencies but it's even more of an improvement in such a situation.)

Conclusion

This proposal seems to be entirely positive from my point of view. The drawbacks are quite small and an opt-in design may make them even more manageable.

Issue 2:
eslint-plugin-react-hooks version: 4.0.4

I have the following custom hook:

export function useForceUpdate() {
const [, setValue] = useState(0);
return useCallback(() => setValue((v) => v + 1), []);
}

But when I use it:

function MyComponent(props) {
const forceUpdate = useForceUpdate();

// ... snip ...

useEffect(() => {
// do stuff
forceUpdate();
}, [foo, bar]);

// ... continue
}

The linter complains (rightfully so):

warning React Hook useEffect has a missing dependency: 'forceUpdate'. Either include it or remove the dependency array

It would useful to have a configuration option to tell the linter that forceUpdate is guaranteed to have a stable identity, so it can give it the same treatment as e.g. useState's callback. Otherwise, I have to disable the rule every time I use the hook!