Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to hot reload without being redirected to root with electron-forge and react

I'm having a problem with electron-forge, which I imagine is a common problem, but I can't seem to find the answer.

I have created a new project with npx create-electron-app and I have installed and setup react, and it's all working just fine.

The problem I have is with the hot reload. I am using react-router-dom for routing, and I've used the MemoryRouter as obviously, I don't have URL's running an electron app. The hot reload is working out of the box, but each time it reloads I get navigated back to the entry point of the app, and I would like to stay at on the current page. The annoying thing is, I can usually see the current page update for a split second before it navigates my back to root. Is there a setting somewhere to prevent this?

Appreciate any help.

like image 590
DrLazer Avatar asked Aug 19 '21 13:08

DrLazer


People also ask

How hot reload works react?

In a bid to solve this problem, developers created several plugins and tools that can cause the DOM to re-render on each save without even doing a full-reload. This is called hot reloading. It works by replacing a module of the application during runtime with an updated one so that it's available for instant use.

How to implement hot reload in electron?

Once Electron has been successfully installed, Open the package.json file and perform the necessary changes under the scripts key. Install electron-reload using npm and save it as a dev dependency. Install electron-reloader using npm and save it as a dev dependency. Both of these respective packages can be used to implement Hot Reload in Electron.

What is hot reloading and how does it work?

This is called hot reloading. It works by replacing a module of the application during runtime with an updated one so that it’s available for instant use. This leads us to talk about Hot Module Replacement (HMR). HMR, as the name implies, can replace modules without restarting the server and can easily be enabled with different bundlers.

How do I use electron reloader in Node JS?

Install electron-reloader as a development dependency: Then add this line to the index.js file: and that’s it! Now when you start the application using electron ., or npm start if you have in your package.json, any change you apply to the application files will be reflected in the application window.

Why do we need to require react-Hot-loader in entry point file?

Lastly, we need to require the react-hot-loader patch into our entry point file: We require this because it’s responsible for patching the code at low-level processing. Let’s test our application to see if the state would be preserved on updates now, we can accomplish this by saving the updates we just made and running the application:


2 Answers

Two things that would certainly cause this,

<Switch>
   <Route path="/" component={RootComponent} />
   <Route path="/test" component={TestComponent} />
</Switch>
  1. Check your routes, do you have the base route without exact keyword?

The above will match all routes to the root route and will land you in the root component. You need to add exact key

<Route exact path="/" component={RootComponent} />
  1. Do you have homepage: "." in package.json or <base href="/"> set in index.html? If yes, remove them.

Homepage: '.' will default to serving from the root.

What are the props you have used in the MemoryRouter? Like the initialIndex, initialEntries etc?

Did you try Hot module replacement? I'm not suggesting this as a fix for this issue but it's a good workaround Electron-forge doc for HMR

 entryPoints: [{
          rhmr: 'react-hot-loader/patch', // react hot module replacement
          name: 'main_window',
          html: './src/renderer/index.html',
          js: './src/renderer/index.js'
        }]

Electron-forge doc says it's not possible to do HMR inside the renderer, can you try the above anyways? It worked for me in the webpack app.

Please provide a minimal reproducible code repo/codesandbox to help you with the fix if the above didn't help. Most importantly, need to see the MemoryRouter usage in your app.

Update in response to the comment:

Yes, electron forge does hot reload by default, only changes to the CSS files are hot reloaded (without refresh), changes to JS files will need a refresh, in both cases files are being watched for changes. You can see note in the webpack-dev-server config (snapshot below)

enter image description here

Looking at your gist on MemoryRouter, I suggest below changes

  1. Provide the memory history prop to the router.

        import {createMemoryHistory} from 'history';
    
        const history = createMemoryHistory();
    
        <Router history={history}>
          <Switch>
            <Route path='/dash' exact component={Dash} />
            <Route path='/wallet' exact component={Wallet} />
            <Route path='/service' exact component={ServiceStatus} />
            <Route path='/' exact component={SignIn} />
            <Route component={SignIn} /> // would suggest protected routes 
          </Switch>
        </Router>
    
  2. Remove exact from other routes than the base route and place base above sign-in.

If the issue persists, I suggest you enable the hot module replacement (which would update your app without reload)

Here is an elaborate writeup on Hot Module Replacement applauded by the co-creator of redux and create-react-app.

A gif on HMR taken from above post (No refresh, so no landing on root route on every change yet the app is updated):

enter image description here

An example app to see it in action.

Electron forge HMR solution

Electron forge react example project

like image 129
deechris27 Avatar answered Oct 28 '22 17:10

deechris27


You can use electron-reloader to achieve this during development. If changes is made on the main process, the main process gets updated. If changes is made to the renderer process, the renderer process gets updated https://www.npmjs.com/package/electron-reloader

Another approach is to log the current route on the render process and save it on the localstorage. You can then go to that route when the page reloads. If you want to keep the state, you might need to save the state when you log the route.

localStorage.setItem('current_route', route)
localStorage.setItem('current_state, the_entire_state)

You can use the necessary lifecycle, to go to the required route and set the state

like image 36
abubakri olaitan Avatar answered Oct 28 '22 19:10

abubakri olaitan