-
Notifications
You must be signed in to change notification settings - Fork 47k
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
[ESLint] Forbid top-level use*() calls #16455
Conversation
Details of bundled changes.Comparing: e89c19d...dfd0407 eslint-plugin-react-hooks
Generated by 🚫 dangerJS |
This is not a change. Just adding more coverage.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the helpful context in the PR description.
}; | ||
tests.valid = tests.valid.filter(predicate); | ||
tests.invalid = tests.invalid.filter(predicate); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice
Note this is a breaking change for the plugin since it would become more aggressive. |
This reverts commit 96eb703.
As of version `^2.0.0` of `eslint-plugin-react-hooks` [1] the plugin now forbids top-level `use*()` calls more aggressively [2]. See the official changelog and corresponding commits [3] for more details. To adapt to this change the peer & dev dependency version has been updated to the latest minor/patch version [4]. [1]: https://github.com/facebook/react/tree/master/packages/eslint-plugin-react-hooks [2]: facebook/react#16455 [3]: https://github.com/facebook/react/pull/16528/files [4]: https://www.npmjs.com/package/eslint-plugin-react-hooks Co-authored-by: Sven Greb <development@svengreb.de> GH-23
As of version `^2.0.0` of `eslint-plugin-react-hooks` [1] the plugin now forbids top-level `use*()` calls more aggressively [2]. See the official changelog and corresponding commits [3] for more details. To adapt to this change the peer & dev dependency version has been updated to the latest minor/patch version [4]. [1]: https://github.com/facebook/react/tree/master/packages/eslint-plugin-react-hooks [2]: facebook/react#16455 [3]: https://github.com/facebook/react/pull/16528/files [4]: https://www.npmjs.com/package/eslint-plugin-react-hooks Co-authored-by: Sven Greb <development@svengreb.de> GH-23
In the initial release of
eslint-plugin-react-hooks/rules-of-hooks
, we forbid this:But we didn't forbid this:
This PR forbids it in the lint rule.
Why did it work before?
We didn't ban it at the time for three reasons:
use*
prefix seemed dicey and we didn't want to push the convention harder than absolutely necessary.history
library whose 2.x versions had an API like this:So banning this pattern would create a false positive for it.
Why ban it now?
If your environment uses "inline requires" (opt-in on React Native), you might not get a crash at all. Instead, the top level initialization of a module may run as a result of some component's render, and so Hooks would accidentally "belong" to the parent. That's confusing. While "inline requires" aren't very common on the web, they're a powerful optimization, so it's plausible they will get used more often with time as build systems add support for them.
Even regardless of that risk, we can confidently say Hooks have been a successful rollout now. So whether the bugs themselves are a problem or not, the
use
convention effectively already strongly implies it's a Hook. From that perspective,use*()
at top level is just confusing to look at.But I'm not using a Hook!
There are some older versions of
history
andreact-router
that haduse
-prefixed APIs for things that aren't Hooks. If you see a false positive, please feel free to suppress it:This is not ideal, but this isn't an issue in recent versions of these libraries — and also most apps only have at most a single file with this issue.
If you for some reason can't add suppressions, you may alternatively:
import { useBasename as withBasename } from 'history'
import * as History from 'history'
andHistory.useBasename()
Note this isn't just to "appease the linter". People expect
use
prefix to only be used by Hooks now, so it's good to push the ecosystem towards consistent naming.What about
MyLibrary.useFoo()
?We warn about invalid use of
use*()
andReact.use*()
, but notMyLibrary.use*()
. This is because initially we saw too many false positives from modules likeMyStore.useNewAnalytics()
.The new top-level error respects the same rule. For example, it would warn for
useBasename()
, but not forHistory.useBasename()
. So that's another escape hatch if you want to suppress it.In the future, we might consider making it stricter, and banning invalid calls to
MyLibrary.use*()
too. But it's less common in general because the convention is to import Hooks directly without a namespace. It's also much more commonly encountered in open source, likeapp.use()
from Express, orjest.useFakeTimers()
. So maybe it's not worth it.