-
Notifications
You must be signed in to change notification settings - Fork 46.3k
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
Consistent useCallback implementation in ReactDOMServer #18783
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 ab9ee0f:
|
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.
Fine for consistency but I think the implementation of useMemo is actually wrong here. We should just break it and never memoize. This is not reliable anyway since suspense will clear it.
There are no guarantees that it'll memoize. If anything we should make it less predictable on the client to ensure that these abuses don't land in the first place. E.g. occasionally drop it in DEV.
It's not worth memoizing everything in the whole page just in case something calls setState in render during initial render, which should be a warning anyway since it only exists for update purposes. So it should never happen on the server initial render. In fact, we should break the whole implementation of setState during initial render on the server and free up that extra work.
I think I know which internal callsite you're referring to but that's poorly structured code relying on setState in render. We should restructure/rewrite that code.
Details of bundled changes.Comparing: 5153267...ab9ee0f react-cache
Size changes (experimental) |
Details of bundled changes.Comparing: 5153267...ab9ee0f react
React: size: 0.0%, gzip: -0.0% Size changes (stable) |
Summary
In ReactDOMServer we implement both useMemo and useCallback. The React docs mention that
useCallback(fn, deps)
is equivalent touseMemo(() => fn, deps)
, however this is not true today as useCallback completely ignores the deps argument.Although the docs also mention that there are not semantic guarantees around memoization for useMemo (and subsequently useCallback), having the implementation differ between these hooks in the server environment can be confusing and lead to hard to track down issues that appear only during server rendering.
Also after reading the docs, I'm not absolutely sure if useCallback is expected to provide semantic guarantees based on the inputs changing. This is very clear for useMemo, but the behavior for useCallback seems somewhat up for debate, since its not explicitly called out.
I think it would be worth updating the docs to make this clear since I've already seen examples of devs relying on callback references to be stable (which is how this came to my attention initially).
Test Plan
Added test case in ReactDOMServerIntegrationHooks-test.js
Also verified that this prevents an infinite render loop on the server when used with code that relies on callback references being stable.