After hot reload, useContext no longer returns the context, I assume the whole context is lost, haven't tried it with a normal consumer.
Hooks are not quite well tested yet.
Try to disable a single feature which may break them (only if you are using hot-patch(webpack-loader or hot-loader/react-dom)
import {setConfig} from 'react-hot-loader';
setConfig({disableHotRenderer: true});
My setup is as follows:
plugins: [new webpack.HotModuleReplacementPlugin()],
and
{
test: /\.(js|jsx)$/,
loader: 'babel-loader',
exclude: /(node_modules)/,
options: {
cacheDirectory: true,
plugins: ['react-hot-loader/babel'],
},
},
I have tried using the disableHotRenderer and it didn't fix the problem.
Then I will ask you to create a repo to reproduce a (exactly yours) problem.
PS: And look like you are not using hot-patch
hot-loader/domI think I was able to repro this.
I did create-react-app, ejected, added hot-loader, and added a simple context and consuming component:
https://github.com/yang/hot-cra-context-repro
Here's a video, where I add a period to App.js鈥攜ou can see from the log statement in the consuming component that it renders twice, first printing 0 (the reset value) before printing 2 (the value it should be):
https://www.youtube.com/watch?v=8b6pVEERdkg
Misc info:
A _new ways_ to get the context, like useContext or even dispatcher.readContext which become popular after "advice".
For now, the best solution is to disableHotRenderer (you have to have hot-patch to keep things working)
Tested it in different ways - it should just fail to hot-render and that's all, context should be still valid.
Edit: Solution to my specific issue as suggested by the next comment.
I am too _loosing the context value_ on Hot Reload (using the useContext() hook). This is my relevant code.
PS: In the index.js you also see a snippet to silence the annoying [HRM] console.logs in the browser console. Found that somewhere on github.
// index.js
const render = Component => (
ReactDOM.render(
<AppContainer>
<Component />
</AppContainer>,
document.getElementById('root')
)
)
render(App)
if (module.hot) {
module.hot.accept('./App', () => { render(App) })
}
// This is a workaround used alongside the webpack-dev-server hot-module-reload feature
// - it's quite chatty on the console, and there's no currently no configuration option
// to silence it. Only used in development.
// Prevent messages starting with [HMR] or [WDS] from being printed to the console
(function(global) {
var console_log = global.console.log
global.console.log = function() {
if (!(
arguments.length == 1 &&
typeof arguments[0] === 'string' &&
arguments[0].match(/^\[(HMR|WDS)\]/)
)) {
console_log.apply(global.console,arguments)
}
}
})(window)
// App.js
import React, {useState, useEffect} from 'react'
import { hot } from 'react-hot-loader'
function App() {
return(<div>Hello World</div>)
}
export default hot(module)(App)
What would happen if in your index.js you will just
ReactDOM.render(<App/>, document.getElementById('root'))
hot(module)(App) is literally wrapping App with AppComponent and calling module.hot.accept, so you have a duplication in your code.
I ran into the same and was able to fix the problem, but it contradicts your documentation.
| Package | Version |
| -------- | ------- |
| react-hot-loader | ^4.12.8 |
| @hot-loader/react-dom | ^16.8.6 |
| react | ^16.8.6 |
Config
index.tsx
require('@babel/polyfill')
const React = require('react')
const App = require('./App').default
const { render } = require('react-dom')
render(<App />, document.getElementById('root'))
export {}
App.tsx
import { hot } from 'react-hot-loader/root'
import React from 'react'
import { Provider } from 'react-redux'
import { Router } from 'react-router-dom'
import history from './history'
import Routes from './getRoutes'
import store from './store'
import { authenticateRoute, readToken, readRegToken } from './routeActions'
import ApolloProvider from './ApolloProvider'
import PageviewTracker from './components/utils/PageviewTracker'
const App = () => (
<ApolloProvider>
<Provider store={store}>
<Router history={history}>
<PageviewTracker>
<Routes
auth={authenticateRoute(store)}
readToken={readToken(store)}
readRegToken={readRegToken(store)}
/>
</PageviewTracker>
</Router>
</Provider>
</ApolloProvider>
)
export default hot(App)
Unlike in @Mykybo's case, we ran into the lost context bug in a class component (consumer). We logged out the context value in the provider and the consumer as well. The provider's value was what we expected, but the consumer only got null. Getting null results in a crash in our application.
By removing react-hot-loader/babel from our .babelrc list, it solved the lost context bug and everything works ok in dev and prod environment as well. The documentation suggests that we should include it in the .babelrc, but as it turned out, everything works without it.
Do you happen to have some idea why this action solved our problem, @theKashey?
Removing babel plugin is not a way to solve the problem. Actually without it (or webpack plugin) context should always be lost on update.
Something is not right here.
馃檧"Oh fuck"馃檧
So #1306 would fix the problem, I would release the fix tomorrow, after another check.
@theKashey Thank you! 馃檪
4.12.9 has been released. Working with and without react-hot-dom patch. Was broken 20 days ago(4.11.0), and honestly the initial problem, and the last problem are not similar, even have roughly the same effect.
I'm getting this issue running "react-hot-loader": "^4.12.15" and using useContext that passes state from a reducer via useReducer. Each reload switches back to initialState rather than persisting it - if that's not expected behaviour I can make an example of it.
No, that's not expected, and RHL does not control this hook. As a result - the only way to switch back to the initial state - remount a component.
Please create an example.
What would happen if in your
index.jsyou will justReactDOM.render(<App/>, document.getElementById('root'))
hot(module)(App)is literally wrappingAppwithAppComponentand callingmodule.hot.accept, so you have a duplication in your code.
Yes, that was indeed the problem. I had to remove both module.hot.accept and the wrapping <AppComponent>
Most helpful comment
馃檧"Oh fuck"馃檧