Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal: react-hooks/exhaustive-deps: a more customizable additionalHooks #18861

Closed
wants to merge 5 commits into from

Conversation

dvoytenko
Copy link

Summary

The current additionalHooks in the react-hooks/exhaustive-deps eslint plugin accepts a regular expression to match hook names. It always assumes the following format:

function useCustomHook(callback, deps) {}

However, this format is not always convenient when other arguments are available in the hook's signature, because the set of dependencies could potentially be large. In those cases, it'd be more convenient to place callback and deps as the last two arguments. For instance, the standard useImperativeHandle has an additional first argument:

function useImperativeHandle(ref, callback, deps) {}

To enable this, the proposal adds a new property: additionalHooksMap that takes a map keyed by a hook name and value specifying callback argument offset.

An example:

[{additionalHooksMap: {
    'useCustomEffect': 1,
    'useAnotherCustomEffect': 2,
    ...
}}]

Test Plan

Added new tests for the new format to the eslint tests.

@facebook-github-bot
Copy link

Hi @dvoytenko!

Thank you for your pull request and welcome to our community.We require contributors to sign our Contributor License Agreement, and we don't seem to have you on file.

In order for us to review and merge your code, please sign at https://code.facebook.com/cla. If you are contributing on behalf of someone else (eg your employer), the individual CLA may not be sufficient and your employer may need to sign the corporate CLA.

If you have received this in error or have any questions, please contact us at cla@fb.com. Thanks!

@codesandbox-ci
Copy link

codesandbox-ci bot commented May 7, 2020

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit f94be69:

Sandbox Source
silly-moore-r4n3e Configuration

@codesandbox-ci
Copy link

codesandbox-ci bot commented May 7, 2020

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit d08cd26:

Sandbox Source
serverless-darkness-j2e3d Configuration

@facebook-github-bot
Copy link

Thank you for signing our Contributor License Agreement. We can now accept your code for this (and any) Facebook open source project. Thanks!

@sizebot
Copy link

sizebot commented May 7, 2020

Details of bundled changes.

Comparing: b41beb1...d08cd26

eslint-plugin-react-hooks

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
eslint-plugin-react-hooks.production.min.js 🔺+1.7% 🔺+1.9% 22.87 KB 23.26 KB 7.7 KB 7.84 KB NODE_PROD
eslint-plugin-react-hooks.development.js +2.2% +2.6% 82.28 KB 84.1 KB 18.81 KB 19.3 KB NODE_DEV

Size changes (stable)

Generated by 🚫 dangerJS against d08cd26

@sizebot
Copy link

sizebot commented May 7, 2020

Details of bundled changes.

Comparing: b41beb1...d08cd26

eslint-plugin-react-hooks

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
eslint-plugin-react-hooks.development.js +2.2% +2.6% 82.29 KB 84.11 KB 18.82 KB 19.31 KB NODE_DEV
eslint-plugin-react-hooks.production.min.js 🔺+1.7% 🔺+1.9% 22.89 KB 23.27 KB 7.7 KB 7.85 KB NODE_PROD

Size changes (experimental)

Generated by 🚫 dangerJS against d08cd26

@swissspidy
Copy link
Contributor

There's a conflict now because of #18907

@dvoytenko
Copy link
Author

Thanks, @swissspidy. Rebased.

@gaearon
Copy link
Collaborator

gaearon commented May 26, 2020

Mind updating? Let's get this in.

@dvoytenko
Copy link
Author

@gaearon Rebased. PTAL.

@gaearon
Copy link
Collaborator

gaearon commented May 27, 2020

I think we might want to think more about the API here. What if you want to use a regex and put it in the map? The existing feature supports regexes. It is also a bit confusing to have two independent options. Why does one of them win? What if a regex matches in one but the key matches in the other one?

@gaearon
Copy link
Collaborator

gaearon commented May 27, 2020

Could be something like

additionalHooks: [
  [{ test: /regex/, callbackIndex: 3 }],
  ...
]

@dvoytenko
Copy link
Author

I think we might want to think more about the API here. What if you want to use a regex and put it in the map? The existing feature supports regexes. It is also a bit confusing to have two independent options. Why does one of them win? What if a regex matches in one but the key matches in the other one?

Sure. That makes sense. I'll update.

@dvoytenko
Copy link
Author

Could be something like

additionalHooks: [
  [{ test: /regex/, callbackIndex: 3 }],
  ...
]

@gaearon PTAL. I updated per your request. The linter schema is now either one of these:

  • A string - the current mode.
  • An array of objects in the shape {test, callbackIndex}

@dvoytenko
Copy link
Author

@gaearon could you ptal to see if this is good to be merged?

@swissspidy
Copy link
Contributor

@gaearon would this be good to go after a rebase?

@swissspidy
Copy link
Contributor

Opened #19644 to track this proposal in case it helps with visibility...

@whatisaphone
Copy link

It might be simpler (for end users) to infer the callback index from callsite usage. All the hooks I've ever seen that take a callback have arguments of (...optionalExtraArgs, callback, deps?). So the callback is always second-to-last, or if it's last, the deps array is undefined.

Are there any callback+deps hooks out in the wild that break this assumption?

@dvoytenko
Copy link
Author

@whatisaphone I think somewhere this was covered as well. Personally, I always order args to have callback and deps as the last 2 (or 1) args. However, the current behavior is exactly the opposite and so we decided to go with a configurable option for backward compatibility.

@MatthijsBon
Copy link

MatthijsBon commented Oct 28, 2020

I would like to add that useDebounce has a different signature than what seems to be proposed here:

const [ ... ] = useDebounce(fn: Function, ms: number, deps: DependencyList = []);

I would say that specifying the index of the callback is a non-complete addition and would suggest to instead specify the index of the DependencyList?

@georeith
Copy link

@MatthijsBon I think you can assume that dependency list is the last argument. I can see why callback may potentially be moved around but that feels like a pretty solid convention thats worth encouraging.

@stale
Copy link

stale bot commented Jun 11, 2021

This pull request has been automatically marked as stale. If this pull request is still relevant, please leave any comment (for example, "bump"), and we'll keep it open. We are sorry that we haven't been able to prioritize reviewing it yet. Your contribution is very much appreciated.

@stale stale bot added the Resolution: Stale Automatically closed due to inactivity label Jun 11, 2021
@dvoytenko
Copy link
Author

bump

@andrenanninga
Copy link

Any chance of getting this or #21719 merged? Would love to see this feature.

@stale
Copy link

stale bot commented Jan 8, 2022

This pull request has been automatically marked as stale. If this pull request is still relevant, please leave any comment (for example, "bump"), and we'll keep it open. We are sorry that we haven't been able to prioritize reviewing it yet. Your contribution is very much appreciated.

@stale stale bot added the Resolution: Stale Automatically closed due to inactivity label Jan 8, 2022
@swissspidy
Copy link
Contributor

bump

@stale stale bot removed the Resolution: Stale Automatically closed due to inactivity label Jan 9, 2022
@vojtech-dobes
Copy link

@gaearon Is there a chance of this being merged and shipped? exhaustive-deps is now very strict and discourages designing a focused API for custom hook, because it's not possible to teach this rule on which position the callback is present.

@kachkaev
Copy link

@dvoytenko would you be willing to re-create this PR against the main branch? Seems like this PR is closed because the master branch has been deleted.

@swissspidy
Copy link
Contributor

Quoting #21719 (comment):

That said, I don't think we will be adding support for this. In general, we've been leaning towards recommending that custom Hooks do not take dependency arrays at all, and that you rely on the built-in Hooks to do that instead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.