vite: HMR breaks when modifying React context provider
Describe the bug
Vite HMR breaks when modifying React context provider Related: https://github.com/vitejs/vite-plugin-react/issues/24
Reproduction
System Info
Output of npx envinfo --system --npmPackages vite,@vitejs/plugin-vue --binaries --browsers
:
System:
OS: macOS 10.15.7
CPU: (8) x64 Intel(R) Core(TM) i7-4870HQ CPU @ 2.50GHz
Memory: 413.26 MB / 16.00 GB
Shell: 5.7.1 - /bin/zsh
Binaries:
Node: 15.14.0 - ~/.nvm/versions/node/v15.14.0/bin/node
Yarn: 1.22.10 - /usr/local/bin/yarn
npm: 7.7.6 - ~/.nvm/versions/node/v15.14.0/bin/npm
Watchman: 4.9.0 - /usr/local/bin/watchman
Browsers:
Brave Browser: 89.1.21.76
Chrome: 90.0.4430.93
Firefox: 87.0
Firefox Developer Edition: 89.0
Safari: 14.0.3
npmPackages:
vite: ^2.2.3 => 2.2.4
Used package manager: npm
Logs
Before submitting the issue, please make sure you do the following
- Read the Contributing Guidelines.
- Read the docs.
- Check that there isn’t already an issue that reports the same bug to avoid creating a duplicate.
- Provide a description in this issue that describes the bug.
- Make sure this is a Vite issue and not a framework-specific issue. For example, if it’s a Vue SFC related bug, it should likely be reported to https://github.com/vuejs/vue-next instead.
- Check that this is a concrete bug. For Q&A open a GitHub Discussion or join our Discord Chat Server.
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Reactions: 57
- Comments: 51 (6 by maintainers)
Same issue here, but im trying to be more specific with that.
In my experience:
Running
npm run dev
works. Forcing a hot reload on this file, crashes (context gets default value for alluseContext
calls).Running
npm run dev
works. Forcing a hot reload on any of those files, still works.Tell me if you need more info, or a minium reproduction repo.
Hope it helps!
I’ve pushed up a PR that fixes this issue, according to a test I wrote based off the reproduction in the issue description. But, it requires a change to how Vite handles
import.meta.hot.invalidate()
, so I think it will need some discussion with the Vite team.@selrond Is there a solution to this problem?
Some correction, Vite 3 is out, however Vite 3’s HMR still didn’t support React Context yet.
Your welcome!
Hence I would not recommend react developers using vite as development tool. Hence, u see Nextjs, ionic, and bunch of huge react frameworks still did not using vite yet. Nextjs, Webpack are much more mature for react development, however vite is more focus on vue 3 based on my understanding 👍
Some add on, React Context is great feature, without React context, We cant build a scalable and huge react project with ease!
For those thumb down reaction, please share your thought and tell me am i say something wrong? Please correct me if im wrong, Thanks!
In my case the context mechanism behind react seems to break - I get 2 renders of the same component:
My config for vite is empty so no other plugins can be influencing this. The only thing that helps is restarting vite (simple reload of the website does not work so it must be caching of HMR even on reloads). Disabling HMR entirely
server.hmr = false
fixes the issue at the cost of no HMR.After changing more things afterwards I suddenly started getting a weird
_s is not defined
in the component even with the most barebones context when HMR kicks in after changing anything. (again fixed by restarting vite).Debug trace from Vite
Stacktraces of the 2 context calls done in the component
console.log(useContext(...))
I’ve traced down the problem to defining the context in the same file where I called
ReactDOM.render
. Since I defined the context here I also export it (to be able to consume it in other components). Since this is the place I call the final render though it’s also the place I import those components which creates a cyclic dependency.The problem then is either the cyclicity and HMR breaking it. Or HMR doing something to the compiled code which creates the context twice which then causes a whole bunch of errors and weird behaviour.
Either way, don’t define context’s in the same file as you call
ReactDOM.render
kids #TILThanks, now I know what’s going on.
DON’T define the context with its provider in the SAME FILE.
HMR will break if any change happen in that file, or any file that is used in the context or the provider.
More about it.
If we have one file with this code:
Any change here, HMR will break.
But separate them into two files:
and
In this way, the issue is resolved, and changes can happen safely everywhere.
I will test it next with a simple mobx store and see what happens.
Update:
After adding a small mobx store, I can confirm, this issue only happens when both context and provider are defined in the same file. Now we need to know, why?
@justinbhopper It works so smooth with no issues. HMR don’t break the provider anymore.
Here’s the steps:
1- create a new vite react ts project. 2- inside App.tsx, add this code:
3- Inside vite.config.ts, add this plugin:
And it works.
Now we just need some better regex matching rules.
Update 1:
Tried this with context in a separated file, it doesn’t work.
To workaround, add this plugin:
and then, wrap
export const CountContext = React.createContext()
with__preserveRef()
likeexport const CountContext = __preserveRef('CountContext', React.createContext());
.stackblitz example
I noticed the 54 likes, the 47 comments, a few duplicate issues, and the implementation of
fastRefresh
property in the configuration, so the issue can have a workaround.The issue doesn’t feel it deserves the
p3-minor-bug 🔨
label.I’m also stuck with issue related to Context and HMR/fast refresh. In my case
createContext
andProvider
are in separated files. If I modify a component withuseContext
, HMR reloads my component but I get an error which means thatuseContext
return default value (the value increateContext
:export const MyContext = createContext({ a: "foo"})
) but I need value fromProvider
(<MyContext.Provider value={b: "bar"}>
)To workaround this issue, I just use
{ fastRefresh: false }
option in@vitejs/plugin-react
which is clearly disappointing when you are used{ fastRefresh: true }
😉It’s still a strong reason to choose nextjs instead of vitejs just because of context losing, in real app, a context losing will easily cause a tab 100% CPU because of an error loop, have to keep a task manager open and kill the tab.
Just ran into this issue on a non-vite project. We are introducing context for the first time into our app. After messing around I finally found that yes moving the createContext call to another file resolves the issue mostly. Editing that file still causes the problem.
@seeker-3 I believe you could use the HMR API to achieve the same: https://vitejs.dev/guide/api-hmr.html#hot-decline
Vite 3 is out, but React context still do not support HMR
I tried the 2nd option, though it does work with HMR. We kind-a lose the capability of Fast Refresh. While fast refresh is still buggy, I think disabling it for now is the only workaround ☹️: https://github.com/vitejs/vite/issues/3301#issuecomment-1080292430
FYI, we stumbled over this problem too, and are using a (somewhat hacky) solution that seems to work, without needing to write Vite plugins or fiddling with HMR API.
The trick is to move the “createContext” call into the provider component. Using a React ref ensures uniqueness.
What do you think? Does this solution have any downsides I am not aware of (except that this has to be repeated for every context, and goes into production code)?
@adnanalbeda I also cannot reproduce the bug using the original repo (https://github.com/selrond/vite-react-usecontext) after upgrading it to
vite@3.0.2
and@vitejs/plugin-react@2.0.0
. Is this bug still occurring in latest?https://stackblitz.com/edit/github-6861mq-hcsekc
thats not hot reload man haha
reference: https://www.geeksforgeeks.org/difference-between-hot-reloading-and-live-reloading-in-react-native/
same issue here, export useContext will be break when hot reload… feeling weird, and im still trying figure out the solution…
i tried this, wont work… I still had to manually refresh everytime when i save work on my vite project tho.
Could anyone tell me which old version did not have this problem, i wish to downgrade temporary to continue work with my project smoothly…
@sodatea can we mark it as major bug?
I found an temporary solution which is downgrade the vite version to v2.5.0 and use
@vitejs/plugin-react-refresh
instead of@vitejs/plugin-react
should works without the Tony’s bug.