-
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
using the wrong renderer's act() should warn #15399
using the wrong renderer's act() should warn #15399
Conversation
via facebook#15319 This solves 2 specific problems - - using the 'wrong' act() doesn't silence the warning - using the wrong act logs a warning It does this by using an empty object on the reconciler as the identity of ReactShouldWarnActingUpdates.current. We also add this check when calling createContainer() to catch the common failure of this happening right in the beginning.
ReactDOM: size: 0.0%, gzip: -0.0% Details of bundled changes.Comparing: 5731e52...26ce8b4 react-dom
react-art
react-native-renderer
react-test-renderer
react-reconciler
Generated by 🚫 dangerJS |
hmm @sizebot you have my attention |
@threepointone sizebot compares to the nearest common ancestor of master and your branch (e5c5935). Because you've merged from master several times since then, the size reduction includes stuff that has already landed. This is one of the reasons I prefer to rebase on top of upstream changes instead of merging them. |
made fixtures/act for act(). specifically, this lets us tests how act behaves when you use the wrong act() for the wrong renderer. also mvoes dom/../act-dom.html to this fixture.
What if I used flushPassiveEffects as the sigil value? 🤔 it would remove the need for the extra exports. EDIT - done. |
* [sizebot] Fail gracefully if CI returns invalid response Moves the `response.json()` call into the catch block. * Stop tracking bundle sizes
…ons (facebook#15402) The Pointer Events spec mentions that the value of `button` in a nativeEvent can be anything between 0 and 5 for "down" events. We only care about those with a value of 0.
via facebook#15319 This solves 2 specific problems - - using the 'wrong' act() doesn't silence the warning - using the wrong act logs a warning It does this by using an empty object on the reconciler as the identity of ReactShouldWarnActingUpdates.current. We also add this check when calling createContainer() to catch the common failure of this happening right in the beginning. make a proper fixture for act() made fixtures/act for act(). specifically, this lets us tests how act behaves when you use the wrong act() for the wrong renderer. also mvoes dom/../act-dom.html to this fixture. cleanup fixtures/dom/.gitignore verify that it 'works' with art+dom verify that it 'works' with art+test augh prettier tweak warning messages
…one/react into renderer-specific-act-warning
add @flow annotation
… act/dom fixture folders
Something to keep in mind is that passive effects are scheduled with Scheduler, and our recommendation will be to use the mock Scheduler build in tests. Which means effects that aren't wrapped by |
^ I believe the reason you didn't encounter this problem in your tests is because the separate fixture test suite you created doesn't use the mock Scheduler build. |
@acdlite how would you feel about landing this before the |
bump |
I can't review this until you resolve the conflicts |
abandoning this for #15756 |
via #15319
So tl;dr this PR -
flushPassiveEffects
function itself) as the value ofReactShouldWarnActingUpdates.current
act()
This solves 2 specific problems -
using the 'wrong'
act()
shouldn't silence the warning:We do this by using a sigil unique to the renderer (as an elegant hack, we use
flushPassiveEffects
as the sigil, removing the need to make a new object).act()
sets this object before the callback, and unsets it when it's over. Then in addition towarnIfNotCurrentlyActingUpdatesInDev()
, we also checkwarnIfNotScopedWithMatchingAct()
to confirm thatReactShouldWarnActingUpdates.current
matches the expected sigil.using the wrong
act()
logs a warning:Using the same above method, we can check whether you're using the right version of act() for your code.
Now, I first added this check only for state hook updates, but it didn't reliably catch the common failure case. Consider the following component -
Let's write a test for it using the shiny new async
act()
This is the golden path - use the correct act with the matching renderer, and you'll get expected behaviour. Here's a quick diagram of the timeline it goes through
Of note, because we can check every time after calling
flushPassiveEffects()
, we can guarantee that theact()
'scope' will stay open until the effects queue is drained. Good.Now, let's use a mismatching
act()
-Now, let's say we'd added our sigil check only for updates, you'd think it would still trigger the warning. However, the timing of things has changed. There are 2 scenarios of how these will be sequenced out. The first, which is the 'good' version -
Because we can't use
flushPassiveEffects()
as expected (ie - it's just a no op for other renderer instances), we have to rely on the browser/jest environment to flush to the 'screen', and then the effects/updates fire. In this 'good' case, at least one set state call happens inside the act scope, so we can do the sigil check and warn that they aren't using the right act version.However, the bad news is that this happens super rarely (in my rough estimation, only 1 in 20 'successes'). In reality, it usually happens outside the scope of the
act()
scope.Here, you'll see that the effects fire after the
act()
scope has closed, so when we do the sigil check, we can only warn that the dev hasn't wrapped their code withact()
(which will confuse them, since they think they already have)So how do we fix this? Well, I noticed that most of these failures happen at the very start, when they initialise (
TestRenderer.create()
,ReactDOM.render()
, etc). I believe that if we also add just the sigil identity check in the reconciler's.createContainer()
, we should be able to warn for most cases asap that they're using the wrong version (and ofc,createContainer
is synchronous and won't escape theact()
scope).A quirk with our codebase is we don't allow multiple renderers in the same test, so I made a fixture folder
fixtures/act
to test these scenarios (see index.test.js for details). I used react-dom / react-test-renderer for the tests but I should probably add react-art as well.Questions -
flushPassiveEffects
as the sigil itself. ok/not ok?