-
-
Notifications
You must be signed in to change notification settings - Fork 458
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
Ensure that state changes are applied immediately on mount #256
Conversation
cc @JoviDeCroock fyi: We still get a double render on mount since it seems that React will schedule a batched update on setState during initial mount instead of aborting to render that component, so this makes set State mutable during initial mount |
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 work, this really makes me wonder how you discover all these things :o lots to learn on my part it seems
@andyrichardson Added some tests for |
It seems that in the current version React does trigger *two* renders in our case. We call executeQuery immediately which has a couple of setStates. These are batched, it seems, but do trigger a second update of the underlying component, which is a shame. Instead, we know that the initial executeQuery can just safely merge its results into the initial state, if it's during the initial mount. This is why useImmediateState is added, which does just that. Not the nicest way to solve this, but the safest until React ships batched updates by default.
e371cb4
to
cc25a0e
Compare
This adds the additionalHooks option to eslint-plugin-react-hooks that will run the exhaustive-deps check on useImmediateEffect as if it was just the regular useEffect hook.
"react-hooks/exhaustive-deps": [ | ||
"warn", | ||
{ | ||
"additionalHooks": "useImmediateEffect" |
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.
❤️this really is such a nice surprise!
setState(action); | ||
} else if (typeof action === 'function') { | ||
const update = (action as any)(initialState.current); | ||
Object.assign(initialState.current, update); |
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.
Alright, totally could be missing something, but don't we need to do the assignment to initialState.current
here to ensure the mutable ref gets updated, i.e.
initialState.current = Object.assign(initialState.current, update);
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.
Nah, the first argument is being assigned to mutably 😀
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.
Ah right, I forgot that Object.assign
mutates the original object 👍
Fix #245
Fix #209 (See 17feeca)
It seems that in the current version React does
trigger two renders in our case.
We call executeQuery immediately which has a couple
of setStates. These are batched, it seems, but
do trigger a second update of the underlying
component, which is a shame.
Instead, we know that the initial executeQuery can
just safely merge its results into the initial
state, if it's during the initial mount.
This is why useImmediateState is added, which does
just that. Not the nicest way to solve this, but
the safest until React ships batched updates by
default.
This is basically a solution that will continue to
ensure that we won't have to add any state-related
stuff outside of
executeQuery