-
-
Notifications
You must be signed in to change notification settings - Fork 90
Add test for proper reaction disposal in StrictMode #119
Conversation
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.
I think I would rather prefer if you would be testing low-level useObserver
since this adds few extras (like memo) in the mix. Would you be so kind to change it, please?
test/observer.test.tsx
Outdated
@@ -115,6 +115,52 @@ function runTestSuite(mode: "observer" | "useObserver") { | |||
}) | |||
}) | |||
|
|||
describe("double-rendering/StrictMode behavior", () => { | |||
// tslint:disable: no-console | |||
let originalConsoleError: typeof console.error |
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.
Please use jest-console
instead of this boilerplate :) It's even used in this test file already :)
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.
Yup. Will do. I don't normally use Jest, so I wasn't aware of that one.
I thought by putting my code inside the |
Well, it's true, but you don't need to test |
Ok. I did originally start to create a separate I'll pull it out into the separate (I'm also playing with a fix; a small change to |
I've tweaked the test name to reflect what it's really checking for.
N.B. Depending on the implementation of a fix, this test might need some extra delays or act() calls to trigger a delayed cleanup before asserting that all is clean.
I've pulled it out into a separate file, and added a second test to verify not just that no console errors were emitted, but that the store is definitely unobserved after unmount. |
Awesome! Looks great. Now to figure a solution ... 🤔 It's most likely silly, but wouldn't something like this work? Can you please try it against tests? const [isMounted, setMounted] = React.useState(false)
const reaction = useRef<Reaction | null>(null)
if (!reaction.current) {
reaction.current = new Reaction(`observer(${baseComponentName})`, () => {
if (isMounted) {
forceUpdate()
}
})
}
React.useEffect(() => {
setMounted(true)
}, []) There is of course problem of lingering Reaction, but @mweststrate already mentioned some way of clearing those up globally, so that's perhaps not an issue to solve here. |
That'll probably work, but the Using a ref achieves the same thing without the extra full round-trip:
This does fix my StrictMode test. I'm just testing out some cleanup code that would dispose the stray reactions. |
(I'll move this test into another PR.)
I've removed my second (leaked observable) test for now: I'll move it into a separate PR as the fix for that is more complicated. I've also added a fix for the StrictMode warning issue, so it might now be possible to consider merging this. |
(Want me to remove |
Yes please, ditch |
|
This is a test to check that observable changes made between the first component render and commit are not lost. It currently fails (and did so before the change in PR mobxjs#119)
I've been testing out this change in our codebase (with 100+ observer components) and it caused a breakage in one particular scenario linked to changes that occurred between render and first commit. I'd already added an extra unit test in #121 to identify an existing issue where changes could be lost, and that test failed both before and after the #119 change. However, running the same test in non-strict mode produced a different behaviour: before #119 it passed, but after my #119 change, it fails, missing the change. I see two options here:
|
* Test cleaning up reactions for uncommitted components * First attempt at a fix for cleaning up reactions from uncommitted components * Use debounce instead of fixed interval * Add unit test for missing observable changes before useEffect runs This is a test to check that observable changes made between the first component render and commit are not lost. It currently fails (and did so before the change in PR #119) * Add test for cleanup timer firing too early for some components This demonstrates (in a slightly contrived way) how, if the cleanup timer fires between a recent component being rendered and it being committed, that it would incorrectly tidy up a reaction for a soon-to-be-committed component. * Update test for missing changes to check Strict and non-Strict mode We had an existing test to check that observable changes between render and commit didn't go missing, but it only checked in Strict mode, and there's a problem with non-Strict mode. * Add cleanup tracking and more tests This adds full cleanup tracking, and even more tests: - we now track how long ago potentially leaked reactions were created, and only clean those that were leaked 'a while ago' - if a reaction is incorrectly disposed because a component went away for a very long time and came back again later (in a way React doesn't even do right now), we safely recreate it and re-render - trap the situation where a change is made to a tracked observable between first render and commit (where we couldn't force an update because we hadn't _been_ committed) and force a re-render - more unit tests * Fix renamed test file When I renamed this file, I forgot the .test. suffix. D'oh. * Extract tracking and cleanup logic out to separate file * Update src/useObserver.ts Co-Authored-By: RoystonS <[email protected]> * Move some more tracking internals into the tracking code
* Test cleaning up reactions for uncommitted components * First attempt at a fix for cleaning up reactions from uncommitted components * Use debounce instead of fixed interval * Add unit test for missing observable changes before useEffect runs This is a test to check that observable changes made between the first component render and commit are not lost. It currently fails (and did so before the change in PR #119) * Add test for cleanup timer firing too early for some components This demonstrates (in a slightly contrived way) how, if the cleanup timer fires between a recent component being rendered and it being committed, that it would incorrectly tidy up a reaction for a soon-to-be-committed component. * Update test for missing changes to check Strict and non-Strict mode We had an existing test to check that observable changes between render and commit didn't go missing, but it only checked in Strict mode, and there's a problem with non-Strict mode. * Add cleanup tracking and more tests This adds full cleanup tracking, and even more tests: - we now track how long ago potentially leaked reactions were created, and only clean those that were leaked 'a while ago' - if a reaction is incorrectly disposed because a component went away for a very long time and came back again later (in a way React doesn't even do right now), we safely recreate it and re-render - trap the situation where a change is made to a tracked observable between first render and commit (where we couldn't force an update because we hadn't _been_ committed) and force a re-render - more unit tests * Fix renamed test file When I renamed this file, I forgot the .test. suffix. D'oh. * Extract tracking and cleanup logic out to separate file * Update src/useObserver.ts Co-Authored-By: RoystonS <[email protected]> * Move some more tracking internals into the tracking code
* Test cleaning up reactions for uncommitted components * First attempt at a fix for cleaning up reactions from uncommitted components * Use debounce instead of fixed interval * Add unit test for missing observable changes before useEffect runs This is a test to check that observable changes made between the first component render and commit are not lost. It currently fails (and did so before the change in PR #119) * Add test for cleanup timer firing too early for some components This demonstrates (in a slightly contrived way) how, if the cleanup timer fires between a recent component being rendered and it being committed, that it would incorrectly tidy up a reaction for a soon-to-be-committed component. * Update test for missing changes to check Strict and non-Strict mode We had an existing test to check that observable changes between render and commit didn't go missing, but it only checked in Strict mode, and there's a problem with non-Strict mode. * Add cleanup tracking and more tests This adds full cleanup tracking, and even more tests: - we now track how long ago potentially leaked reactions were created, and only clean those that were leaked 'a while ago' - if a reaction is incorrectly disposed because a component went away for a very long time and came back again later (in a way React doesn't even do right now), we safely recreate it and re-render - trap the situation where a change is made to a tracked observable between first render and commit (where we couldn't force an update because we hadn't _been_ committed) and force a re-render - more unit tests * Fix renamed test file When I renamed this file, I forgot the .test. suffix. D'oh. * Extract tracking and cleanup logic out to separate file * Update src/useObserver.ts Co-Authored-By: RoystonS <[email protected]> * Move some more tracking internals into the tracking code
This reverts commit bf3a6c9.
* Schedule uncommitted reaction cleanup (#121) * Test cleaning up reactions for uncommitted components * First attempt at a fix for cleaning up reactions from uncommitted components * Use debounce instead of fixed interval * Add unit test for missing observable changes before useEffect runs This is a test to check that observable changes made between the first component render and commit are not lost. It currently fails (and did so before the change in PR #119) * Add test for cleanup timer firing too early for some components This demonstrates (in a slightly contrived way) how, if the cleanup timer fires between a recent component being rendered and it being committed, that it would incorrectly tidy up a reaction for a soon-to-be-committed component. * Update test for missing changes to check Strict and non-Strict mode We had an existing test to check that observable changes between render and commit didn't go missing, but it only checked in Strict mode, and there's a problem with non-Strict mode. * Add cleanup tracking and more tests This adds full cleanup tracking, and even more tests: - we now track how long ago potentially leaked reactions were created, and only clean those that were leaked 'a while ago' - if a reaction is incorrectly disposed because a component went away for a very long time and came back again later (in a way React doesn't even do right now), we safely recreate it and re-render - trap the situation where a change is made to a tracked observable between first render and commit (where we couldn't force an update because we hadn't _been_ committed) and force a re-render - more unit tests * Fix renamed test file When I renamed this file, I forgot the .test. suffix. D'oh. * Extract tracking and cleanup logic out to separate file * Update src/useObserver.ts Co-Authored-By: RoystonS <[email protected]> * Move some more tracking internals into the tracking code * 2.0.0-alpha.0 * 2.0.0-alpha.1 * 2.0.0-alpha.2 * Upgrade to React 16.9 * Add dedup script and run it * Remove deprecated hooks * Increase size limit * Remove note about Next version * Remove unused productionMode util * Improve readme * Pin dependencies * Merge master properly * Ignore build cache files * Revert removal of tsdx dep * Remove .browserlistrc * 2.0.0-alpha.3 * Bundling need to use build tsconfig * 2.0.0-alpha.4 * Remove object destructuring from optimizeForReactDOM/Native (#240) * Preserve generics when using `observer` (#244) * Preserve generics when using `observer` * Remove any casting from statics as it's no longer needed * Re-add overloads for explicitly specifying props type * Allow for passing options without `forwardRef` * Merge new `observer` overloads * Remove copy of UMD bundle * 2.0.0-alpha.5 * Batched updates are mandatory * Replace .npmignore with files field * Fix tests * Increase size limit Co-authored-by: Royston Shufflebotham <[email protected]> Co-authored-by: Renovate Bot <[email protected]> Co-authored-by: Tarvo R <[email protected]> Co-authored-by: Lukáš Novotný <[email protected]>
This is a PR for a test to illustrate the issue with Concurrent Mode (and, more problematic, in StrictMode), as requested in #53 (comment)
(It currently fails, so you may not want to merge this right now...)