Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

page is not rendering when I click back button with react-router

I have an application that has this top level component:

import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter as Router } from 'react-router-dom';
import { Provider } from 'react-redux';
import { createStore } from '../lib/Store.js';

import Application from '../components/application';

document.addEventListener('DOMContentLoaded', () => {
  ReactDOM.render(
    <Provider store={createStore()}>
      <Router>
        <Application />
      </Router>
    </Provider>,
    document.body.appendChild(document.createElement('div'))
  );
});

When I click on a <Link>, the page renders properly, but if I go back with the browser (Chrome 60.0.3112.113 on MacOS), the page is blank.

There is a very weird but repeatable scenario:

  • Navigate to any page -> page renders properly
  • Click <Link> -> page renders properly
  • Click back button -> blank page
  • Click forward button -> blank page
  • Click back button -> page from step 1 renders!!
  • Click forward -> No render change, the page from step 1 stays rendered
  • Click back -> blank page renders again
  • Click forward -> still a blank page
  • Click back -> page from step 1 renders again...

It seems that every other time I click it, the back button works. The thing is, the original <Link> no longer works when I get the original page to render every other back click. It takes me to the right url, but the page is blank.

I'm sure this has to do with lifecycle callbacks or something of the like, but I can't figure out how to force an update in the correct place to fix the situation.

For clarity, this is what the Application component consists of:

import React from 'react';
import { Route, Switch } from 'react-router-dom';
import PropTypes from 'prop-types';

import TopNav from './TopNav';
import BoardsDashboard from './BoardsDashboard';
import BoardContainer from './BoardContainer';
import CardContainer from './CardContainer';

import { fetchBoards } from '../actions/BoardActions';

class Application extends React.Component {
  static contextTypes = {
    store: PropTypes.object
  }

  render() {
    return (
      <div>
        <TopNav />

        <Route path='/cards/:cardId' exact component={BoardContainer} />
        <Route path='/cards/:cardId' exact component={CardContainer} />
        <Route path='/boards/:boardId' exact component={BoardContainer} />

        <Route path='/' exact component={BoardsDashboard} />
      </div>
    );
  }
}

export default Application;

Using redux-devtools I can see all of the correct actions being dispatched each time I click the back and forward button. I think that my components are not updating because there is no change to the store when these actions complete, but I need them to render even with no change.

I do have some React.Component classes as container components when I need to access the store manually. Whenever I don't need to access the store manually, I use connect from react-redux. TopNav is a presentational component though, so at the very least it should render since it doesn't rely on the store (at least I think it should).

like image 246
Brandon Avatar asked Sep 25 '17 00:09

Brandon


1 Answers

This ended up being Turbolinks reacting to the back button as well as React Router. I removed Turbolinks from my Rails app and the problem is resolved.

like image 200
Brandon Avatar answered Nov 15 '22 03:11

Brandon