Skip to content
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

Fix:- Improve HOC support and state preservation in React Refresh #30660

Merged
merged 4 commits into from
Jan 24, 2025

Conversation

Biki-das
Copy link
Contributor

@Biki-das Biki-das commented Aug 12, 2024

Summary

This fixes #30659 , the issue was how the state was preserved and needed special cases for the forward and memo, have also added tests related to the same.

How did you test this change?

yarn test packages/react-refresh/src/__tests__/ReactFresh-test.js

Screenshot 2024-08-12 at 4 27 39 PM

Copy link

vercel bot commented Aug 12, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
react-compiler-playground ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jan 7, 2025 0:43am

@react-sizebot
Copy link

react-sizebot commented Aug 12, 2024

Comparing: ae9017c...e693246

Critical size changes

Includes critical production bundles, as well as any change greater than 2%:

Name +/- Base Current +/- gzip Base gzip Current gzip
oss-stable/react-dom/cjs/react-dom.production.js = 6.68 kB 6.68 kB +0.05% 1.83 kB 1.83 kB
oss-stable/react-dom/cjs/react-dom-client.production.js = 514.24 kB 514.24 kB = 91.73 kB 91.73 kB
oss-experimental/react-dom/cjs/react-dom.production.js = 6.69 kB 6.69 kB +0.11% 1.83 kB 1.83 kB
oss-experimental/react-dom/cjs/react-dom-client.production.js = 557.28 kB 557.28 kB = 98.97 kB 98.97 kB
facebook-www/ReactDOM-prod.classic.js = 595.79 kB 595.79 kB = 104.85 kB 104.85 kB
facebook-www/ReactDOM-prod.modern.js = 586.21 kB 586.21 kB = 103.30 kB 103.30 kB
oss-experimental/react-refresh/cjs/react-refresh-runtime.development.js +11.69% 12.36 kB 13.80 kB +6.77% 2.98 kB 3.18 kB
oss-stable-semver/react-refresh/cjs/react-refresh-runtime.development.js +11.69% 12.36 kB 13.80 kB +6.77% 2.98 kB 3.18 kB
oss-stable/react-refresh/cjs/react-refresh-runtime.development.js +11.69% 12.36 kB 13.80 kB +6.77% 2.98 kB 3.18 kB
facebook-www/ReactFreshRuntime-dev.classic.js +11.68% 12.37 kB 13.82 kB +6.68% 2.99 kB 3.19 kB
facebook-www/ReactFreshRuntime-dev.modern.js +11.68% 12.37 kB 13.82 kB +6.68% 2.99 kB 3.19 kB

Significant size changes

Includes any change greater than 0.2%:

Expand to show
Name +/- Base Current +/- gzip Base gzip Current gzip
oss-experimental/react-refresh/cjs/react-refresh-runtime.development.js +11.69% 12.36 kB 13.80 kB +6.77% 2.98 kB 3.18 kB
oss-stable-semver/react-refresh/cjs/react-refresh-runtime.development.js +11.69% 12.36 kB 13.80 kB +6.77% 2.98 kB 3.18 kB
oss-stable/react-refresh/cjs/react-refresh-runtime.development.js +11.69% 12.36 kB 13.80 kB +6.77% 2.98 kB 3.18 kB
facebook-www/ReactFreshRuntime-dev.classic.js +11.68% 12.37 kB 13.82 kB +6.68% 2.99 kB 3.19 kB
facebook-www/ReactFreshRuntime-dev.modern.js +11.68% 12.37 kB 13.82 kB +6.68% 2.99 kB 3.19 kB

Generated by 🚫 dangerJS against ec4517f

@Biki-das
Copy link
Contributor Author

@gaearon did you encounter this error? if yes could you help me out if this fix looks right.

@Biki-das
Copy link
Contributor Author

Biki-das commented Oct 3, 2024

cc @josephsavona
Might be something to fix. would love to know your thoughts

@hoxyq
Copy link
Contributor

hoxyq commented Oct 16, 2024

Hey @Biki-das, apologies for a long wait. I think we should find an owner for react-refresh, I am not sure when was the last time react-refresh was actually updated.

@Biki-das
Copy link
Contributor Author

hi @hoxyq 😅 no worries, i understand the team have other priorities and i guess dan was requested for review while ago, but since he is no more actively a part of the react team, so might not be something that gets attention, yeah the last change was long back, but this seems to be an important bug that shall be fixed as this occurs in Nextjs as well.
yeah we should find someone who knows about the react refresh code.

@Biki-das
Copy link
Contributor Author

@hoxyq any update on this,
may be @poteto

@hoxyq
Copy link
Contributor

hoxyq commented Nov 18, 2024

@hoxyq any update on this,

may be @poteto

Hey, @Biki-das, no updates from me, I am currently on leave and will be back in December.

@Biki-das
Copy link
Contributor Author

Biki-das commented Jan 1, 2025

@hoxyq whenever you return and if you are a bit less busy, could you forward this further to someone who might have idea about react refresh, feel like this fix could be important.

@Biki-das
Copy link
Contributor Author

@eps1lon any thoughts on who can review this, i see react refresh has not been touched for a long time? could we get someone to review this if you know someone.

Copy link
Contributor

@hoxyq hoxyq left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall looks good, and changes make sense, few points:

  • Could you please retitle this PR to something that describes what's being added to Fresh?
  • Could you please add tests that will check that state is not preserved when switching between different wrappers?

@Biki-das
Copy link
Contributor Author

@hoxyq thanks for the feedback sure i will try to add the required tests and change the PR title as well.

@Biki-das
Copy link
Contributor Author

Biki-das commented Jan 22, 2025

@hoxyq let me know if the new tests added are what you expected, and the reset test is running fine.

@Biki-das Biki-das changed the title Fix:- fixed HMR issue Fix:- Improve HOC support and state preservation in React Refresh Jan 22, 2025
@Biki-das
Copy link
Contributor Author

Overall looks good, and changes make sense, few points:

  • Could you please retitle this PR to something that describes what's being added to Fresh?
  • Could you please add tests that will check that state is not preserved when switching between different wrappers?

also nothing new is added to Fresh, these are the changes

Added special handling for React.forwardRef and React.memo components
Enhanced state preservation logic between updates
Added checks for component type signatures and React component types
Improved family registration for HOCs

@Biki-das Biki-das requested a review from hoxyq January 22, 2025 17:50
Biki-das

This comment was marked as duplicate.

@hoxyq
Copy link
Contributor

hoxyq commented Jan 24, 2025

Thanks!

@hoxyq hoxyq merged commit de1eaa2 into facebook:main Jan 24, 2025
188 checks passed
github-actions bot pushed a commit that referenced this pull request Jan 24, 2025
…0660)

## Summary

This fixes #30659 , the issue was how the state was preserved and needed
special cases for the forward and memo, have also added tests related to
the same.
## How did you test this change?

`yarn test packages/react-refresh/src/__tests__/ReactFresh-test.js`

![Screenshot 2024-08-12 at 4 27
39 PM](https://github.com/user-attachments/assets/2b597a62-c45f-443b-acfc-3232962ba0a3)

DiffTrain build for [de1eaa2](de1eaa2)
@Biki-das Biki-das deleted the react-refresh-fix branch January 24, 2025 12:31
github-actions bot pushed a commit to code/lib-react that referenced this pull request Jan 24, 2025
…cebook#30660)

## Summary

This fixes facebook#30659 , the issue was how the state was preserved and needed
special cases for the forward and memo, have also added tests related to
the same.
## How did you test this change?

`yarn test packages/react-refresh/src/__tests__/ReactFresh-test.js`

![Screenshot 2024-08-12 at 4 27
39 PM](https://github.com/user-attachments/assets/2b597a62-c45f-443b-acfc-3232962ba0a3)

DiffTrain build for [de1eaa2](facebook@de1eaa2)
@gaearon
Copy link
Collaborator

gaearon commented Jan 24, 2025

Why is this necessary? What set of tooling does that reproduce with?

These are supposed to be handled by the module bundler. If we switch between a function and memo, I would expect “is exporting only functions” to switch from true to false. From what I remember, in that case the modules that depend on this code are expected to start using the new versions directly (without trying to proxy the implementations). So it should “just work”.

I’m not convinced this is a correct or necessary fix. I would need to read more closely through the code to say for sure. But I would encourage to check the React Native (Metro) or the webpack plugin behavior instead of testing this in isolation. If they handle it with the existing code (which I assume they do — I tested these cases when working on FR), I don’t think this change is needed.

@gaearon
Copy link
Collaborator

gaearon commented Jan 24, 2025

If CodeSandbox or Next.js aren’t handling this correctly, I would first assume that this is a problem with their integrations of FR. We need to verify whether this works in the original Metro one.

@gaearon
Copy link
Collaborator

gaearon commented Jan 24, 2025

Sorry, i should’ve explicitly marked this as “needs revision” instead of stalling on the review. I sent a revert in #32214. We don’t have to merge it right now but I think this needs a more careful analysis.

@Biki-das
Copy link
Contributor Author

Biki-das commented Jan 24, 2025

@gaearon i happened to discover this even using vitebundler with React, so i assumed react refresh to be the issue and just played with the same, tried to see why it is breaking, apologize if this wasn't the correct way since i had limited understanding.

@hoxyq
Copy link
Contributor

hoxyq commented Jan 24, 2025

We need to verify whether this works in the original Metro one.

Switching between forwardRef and memo wrappers works for me with Metro runtime. Thanks for the explanation.

I am not sure I am following how is the API surface of integration with FR looks like in this case:

I would expect “is exporting only functions” to switch from true to false. From what I remember, in that case the modules that depend on this code are expected to start using the new versions directly (without trying to proxy the implementations)

I can look up a bit later how Metro does that and check if there is anything special.

@Biki-das
Copy link
Contributor Author

Biki-das commented Jan 24, 2025

thanks for the detailed explanation i tried using CRA as it uses webpack and it seems to have the same issue reproduced. and as i understood what dan meant is module bundlers are expected to handle the case which i introduced, rather than the runtime itself.

the component is not a function error log is the same i saw with vite as well.

Screen.Recording.2025-01-24.at.11.43.11.PM.mov

@Biki-das
Copy link
Contributor Author

Biki-das commented Jan 24, 2025

another interesting observation tried the same for react native as of now using expo and i see the same behaviour, @hoxyq did you did the way i did? i seemed to reproduce and see the same error.

the only way i managed to see the different wrapper being rendered below is hitting reload as in the browser refreshing it and here reloading the bundler, else it does not seem to update even after hitting save.

Screen.Recording.2025-01-25.at.12.05.46.AM.mov

the web version from the expo client even goes through the same issue

Screen.Recording.2025-01-25.at.12.18.53.AM.mov

cc @gaearon

@hoxyq
Copy link
Contributor

hoxyq commented Jan 24, 2025

@hoxyq did you did the way i did?

Actually, no. With the same code that is in your demo, I can also reproduce this issue. Both with default and named exports.

Previously I would just wrap Component in React.memo or React.forwardRef and export it, but looks like what you actually need is to preserve a name of what you are exporting, and switch it from plain function to wrappers with memo or forwardRef, like what you are doing in your demo with Component.

@Biki-das
Copy link
Contributor Author

Yeah that's the exact issue, while editing code, the changes should reflect without any issue!

@Biki-das
Copy link
Contributor Author

Biki-das commented Jan 26, 2025

Have verified the changes that i made in the refresh file whether they actually work or not, as test in isolation might not tell the true story, it does work, for CRA i tried configuring it with crago and pulled up my react-refresh-runtime.development.js file which has the fixes to be used. and there were no errors as we currently face.

i have wrapped up a repo to try and test the same, feel free to checkout and let me know if i did something wrong and this is not the way to test the same.

https://github.com/Biki-das/React-refresh-fix-check

Screen.Recording.2025-01-26.at.7.05.49.PM.mov

As Dan said, these might not be the way to fix this, so we need to investigate this further. i am still confused on the part where these should be handled by the bundlers and not the refresh runtime.

cc @hoxyq @gaearon

gaearon added a commit that referenced this pull request Mar 18, 2025
…resh" (#32214)

Reverts #30660

I don’t feel confident in the approach. This part of code is supposed to
rely on the module bundler behaving as expected. _Maybe_ this is correct
but I need to review it closer — it was intentionally _not_ implemented
this way originally.

I’ll try to take a closer look some time this week. We don’t have to
merge this revert right now but just flagging that I don’t understand
the thinking behind the new approach and don’t have confidence in it.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Bug: React refresh fails when component type is changed to memo or forward ref and vice versa
5 participants