Search code examples
javascriptreactjswebpackreact-routerreact-hot-loader

React-Router@4: Routes not switching normally with [email protected]


I am building a React Application with React-Router@4 and [email protected] and Webpack@2^.

Strange things happening,

i have routes declared in routes.js file like this

/* global __DEV__ */
import React from 'react';
import { Switch, Route, Link } from 'react-router-dom';

// import asyncRoute from './asyncRoute';
// const Welcome = asyncRoute(() => import('../views/Welcome'));
// const About = asyncRoute(() => import('../views/About'));
// const Topics = asyncRoute(() => import('../views/Topics'));

import Welcome from '../views/Welcome';
import About from '../views/About';
import Topics from '../views/Topics';

const Routes = ({ ...properties }) => {
  return (
    <div>
      <div>
        Dummy Links to check Code Splitting
        <ul>
         <li><Link to="/">Welcome</Link></li>
         <li><Link to="/about">About</Link></li>
         <li><Link to="/topics">Topics</Link></li>
       </ul>
      </div>
      <Switch>
        <Route exact path="/" component={Welcome} />
        <Route path="/about" render={(props) => <h3>About</h3>} />
        <Route path="/topics" component={Topics} />
      </Switch>
    </div>
  );
}

export default Routes;

// This will enable/force Hot Module replacement on __DEV__ environment.
// if (__DEV__) {
//   require('../views/Welcome');
//   require('../views/About');
//   require('../views/Topics');
// }

My Main.js File looks like this,

import React from 'react';
import ReactDOM from 'react-dom';
import { AppContainer } from 'react-hot-loader';

import configureStore from './redux/configureStore';

const initialState = window.__INITIAL_STATE__;
const store = configureStore(initialState);

import './styles/main.css';

import Root from './views/Root';

function render(Root) {
  ReactDOM.render(
    <AppContainer>
      <Root store={ store } />
    </AppContainer>,
    document.getElementById('root')
  );
}

if (module.hot) {
  module.hot.accept('./views/Root', () => {
    const nextRoot = require('./views/Root').default;
    render(nextRoot);
  });
}

render(Root);

Normal routes switching is not happening, you can see attached video below

https://share.viewedit.com/XbjKCUjbcvhcL3xRXm8kX7

From the video, it looks like normally clicking on the Links is not re-rendering is not happening but when i change something in some component, react-hot-loader patching is happening at the time the switched path is rendered.

My Project lies in this path https://github.com/bboysathish/react-boilerplate/tree/dev

How can i solve this issue ?


Solution

  • Actually, it turns out to BE blocking of context propagation.

    Please perform the following diff to have your application work like you expect it to:

    diff --git a/app/routes/Routes.js b/app/routes/Routes.js
    index 2b9b787..45dbcbf 100644
    --- a/app/routes/Routes.js
    +++ b/app/routes/Routes.js
    @@ -22,7 +22,7 @@ const Routes = ({ ...properties }) => {
              <li><Link to="/topics">Topics</Link></li>
            </ul>
           </div>
    -      <Route path="/" component={Welcome} />
    +      <Route path="/" exact component={Welcome} />
           <Route path="/about" component={About} />
           <Route path="/topics" component={Topics} />
         </div>
    diff --git a/app/views/App.js b/app/views/App.js
    index 405414c..c712c3a 100644
    --- a/app/views/App.js
    +++ b/app/views/App.js
    @@ -1,5 +1,6 @@
     import React, { Component } from 'react';
     import { connect } from 'react-redux';
    +import { withRouter } from "react-router-dom";
    
     class App extends Component {
       render() {
    @@ -12,4 +13,4 @@ class App extends Component {
       }
     }
    
    -export default connect()(App);
    +export default withRouter(connect()(App));
    

    Let's dive into it a bit:

    -export default connect()(App);
    +export default withRouter(connect()(App));
    

    This will make sure your connected component is responding to context changes. React-redux is not re-rendering the component on context change, and it's a known issue.

    -      <Route path="/" component={Welcome} />
    +      <Route path="/" exact component={Welcome} />
    

    This will make sure your Welcome component is only rendered on the exact / URL.