-
Notifications
You must be signed in to change notification settings - Fork 47.9k
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
Add ESLint Rule for Safe Ref Usage #19095
Conversation
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 e521c8a:
|
Details of bundled changes.Comparing: 4c7036e...e521c8a eslint-plugin-react-hooks
Size changes (stable) |
Details of bundled changes.Comparing: 4c7036e...e521c8a eslint-plugin-react-hooks
Size changes (experimental) |
@louisscruz You point at a comment talking about a very specific use case where a ref is used inside a With the examples you provide, you simply state: 'this is not safe'. Could you explain how these constructs could cause problems? |
If one branch’s rendering is interrupted, but its rendering has the side effect of mutating a ref, that ref value will still have been mutated and retain the value intended for that branch rendering in other branch renderings. |
@louisscruz Thank you for responding. It however does not help me understanding the problematic nature. How can we achieve the same instance of a component to end up in two branches? |
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. |
Closing this pull request after a prolonged period of inactivity. If this issue is still present in the latest release, please ask for this pull request to be reopened. Thank you! |
Summary
Mutating a given ref's
current
property as the result of a render or hook call is not safe in concurrent mode. The reason for this is described here.As an example, this is not safe:
This also wouldn't be safe:
There currently isn't a guard rail in place to prevent applications not written for concurrent mode first to easily identify this problem before the application is opted-in to concurrent mode. Without a guard rail, applications that move from non-concurrent mode to concurrent mode are at some point are at a serious risk of experiencing cumbersome regressions as a result of the move.
So, I'm proposing an ESLint rule that fails in the case that any top-level ref mutations are found and suggests that they be moved into either
useEffect
oruseLayoutEffect
hook calls so that way the mutation only occurs in the case that a commit to render has happened.At the time that this PR is opened, the rule is called
safe-ref-mutations
. It is initially not marked as recommended because I'd like to get some core React contributor guidance first.This rule didn't seem to fit in with either
rules-of-hooks
orexhaustive-deps
, so I wrote it as its own rule. If there's a preference to move it into one or the other, I'm happy to do so. But in general, I wonder if there are more rules that React should have in place for safe concurrency mode usage. Maybe some kind ofsafe-concurrency
rule would be better?As part of this PR, I needed some functions that accomplished the same as those in
RulesOfHooks.js
, so I've extracted them into autils.js
for re-use.If there's a preference that I open an issue for this, I'm happy to do so.
Test Plan
The ESLint rule will be heavily tested if this is the route that is chosen.