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

React context lost on reload when loading it with useContext hook #1207

Closed
Mykybo opened this issue Mar 19, 2019 · 18 comments
Closed

React context lost on reload when loading it with useContext hook #1207

Mykybo opened this issue Mar 19, 2019 · 18 comments
Assignees
Labels

Comments

@Mykybo
Copy link

Mykybo commented Mar 19, 2019

After hot reload, useContext no longer returns the context, I assume the whole context is lost, haven't tried it with a normal consumer.

@theKashey
Copy link
Collaborator

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});

@Mykybo
Copy link
Author

Mykybo commented Mar 19, 2019

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.

@theKashey
Copy link
Collaborator

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

@yang
Copy link

yang commented Apr 26, 2019

I 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—you 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:

  • node -v: 10.15.1
  • npm -v: 6.8.0
  • yarn -v: 1.13.0
  • Operating system: MacOS 10.14.4
  • Browser and version: Chrome 73.0.3683.103

@theKashey
Copy link
Collaborator

theKashey commented Apr 26, 2019

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)

@theKashey
Copy link
Collaborator

Tested it in different ways - it should just fail to hot-render and that's all, context should be still valid.

@anarchist912
Copy link

anarchist912 commented Jul 18, 2019

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)

@theKashey
Copy link
Collaborator

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.

@kristofdombi
Copy link

I ran into the same and was able to fix the problem, but it contradicts your documentation.

Details


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.

Solution

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?

@theKashey
Copy link
Collaborator

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.

@theKashey
Copy link
Collaborator

🙀"Oh fuck"🙀

@theKashey theKashey self-assigned this Jul 22, 2019
@theKashey theKashey added the bug label Jul 22, 2019
@theKashey
Copy link
Collaborator

So #1306 would fix the problem, I would release the fix tomorrow, after another check.

@kristofdombi
Copy link

@theKashey Thank you! 🙂

theKashey added a commit that referenced this issue Jul 23, 2019
Update Context Provider, fixes #1207
@theKashey
Copy link
Collaborator

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.

@anthify
Copy link

anthify commented Nov 1, 2019

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.

@theKashey
Copy link
Collaborator

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.

@anarchist912
Copy link

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.

Yes, that was indeed the problem. I had to remove both module.hot.accept and the wrapping <AppComponent>

@JemarJones
Copy link

I'm experiencing this exact same issue on 4.13.0 right now 😕

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

7 participants