Using Browser buttons, gets rendered page out of sync with path
See original GitHub issueMy routing seems to work fine. But when I use the browser ‘back’ button, the URL changes correctly, but the page then doesn’t match the URL. The first time I hit the back button, nothing happens. Then second time I click it goes to where it should have gone the first time.
This is my entry point: index.tsx:
{UserStore} from './data/stores/UserStore';
declare let module: any;
import * as React from "react";
import * as ReactDOM from "react-dom";
import {AppContainer} from 'react-hot-loader';
import { Router } from 'react-router';
// import createHistory from 'history/createBrowserHistory';
import createHistory from 'history/createHashHistory';
import { Provider } from 'mobx-react';
import { RouterStore, syncHistoryWithStore } from 'mobx-react-router';
import { App } from "./components/app/App";
const history = createHistory();
const routingStore = new RouterStore();
const users = new UserStore();
const synchronizedHistory = syncHistoryWithStore(history, routingStore);
const stores = {
routing: routingStore,
users: users
};
const renderApp = (Component: any) =>
{
ReactDOM.render(
<AppContainer>
<Provider {...stores}>
<Router history={synchronizedHistory}>
<Component />
</Router>
</Provider>
</AppContainer>,
document.getElementById("app_content")
);
};
renderApp(App);
// Hot Module Replacement API
if (module.hot) {
module.hot.accept('./components/app/App', () => {
renderApp(App)
});
}
My app file:
import 'bootstrap';
import * as React from 'react';
import {TopNav} from '../topnav/TopNav';
import {History} from 'history';
import {Routes} from './Routes';
import {inject, observer} from 'mobx-react';
import {UserStore} from '../../data/stores/UserStore';
import {Level, Logger} from '../../util/Logger';
interface IAppProps { routing: History, users: UserStore }
@inject('routing')
@observer
export class App extends React.Component<IAppProps, undefined>
{
//noinspection JSMethodCanBeStatic,JSUnusedLocalSymbols
private log(msg: string, level?: Level): void
{
Logger.get().log(msg, 'App', level || Level.TRACE);
}
render(): JSX.Element
{
const { location } = this.props.routing;
return (
<div>
<TopNav/>
<div className='container body-content'>
<Routes/>
<div className='small'>path: {location.pathname}</div>
</div>
</div>);
}
}
My routes file:
import * as React from 'react';
import {Route, Switch} from 'react-router-dom';
import {HomePage, PageOne, PageThree, PageTwo} from '../home/HomePage';
import {PendingDeliveryPage} from '../delivery/PendingDeliveryPage';
import {DeliveryExecutePage} from '../delivery/DeliveryExecutePage';
export class Routes extends React.Component<undefined, undefined>
{
public render(): JSX.Element
{
return (
<Switch>
<Route exact path='/' component={HomePage} />
<Route path='/delivery/:id/execute' component={DeliveryExecutePage} />
<Route path='/delivery' component={PendingDeliveryPage} />
<Route path='/one' component={PageOne} />
<Route path='/two' component={PageTwo} />
<Route path='/three' component={PageThree} />
</Switch>
);
}
}
And lastely my test pages:
import * as React from "react";
import {Link, RouteComponentProps} from 'react-router-dom';
export class HomePage extends React.Component<RouteComponentProps<any>, undefined>
{
public render(): JSX.Element
{
return (
<div>
<h1>Home</h1>
<ul>
<li><Link to="/">Home</Link></li>
<li><Link to="/one">One</Link></li>
<li><Link to="/two">Two</Link></li>
<li><Link to="/three">Three</Link></li>
</ul>
</div>);
}
}
export class PageOne extends React.Component<RouteComponentProps<any>, undefined>
{
public render(): JSX.Element
{
return (
<div>
<h1>Page One</h1>
<ul>
<li><Link to="/">Home</Link></li>
<li><Link to="/one">One</Link></li>
<li><Link to="/two">Two</Link></li>
<li><Link to="/three">Three</Link></li>
</ul>
</div>);
}
}
export class PageTwo extends React.Component<RouteComponentProps<any>, undefined>
{
public render(): JSX.Element
{
return (
<div>
<h1>Page Two</h1>
<ul>
<li><Link to="/">Home</Link></li>
<li><Link to="/one">One</Link></li>
<li><Link to="/two">Two</Link></li>
<li><Link to="/three">Three</Link></li>
</ul>
</div>);
}
}
export class PageThree extends React.Component<RouteComponentProps<any>, undefined>
{
public render(): JSX.Element
{
return (
<div>
<h1>Page Three</h1>
<ul>
<li><Link to="/">Home</Link></li>
<li><Link to="/one">One</Link></li>
<li><Link to="/two">Two</Link></li>
<li><Link to="/three">Three</Link></li>
</ul>
</div>);
}
}
You can click
- Start at ‘Home’
- Click ‘One’
- Click ‘Two’
- Click ‘Three’, and everthing should be fine.
- Click Browser Back, path changes to /two, but page does not render anything new.
- Click Browser Back and path changes to /one, and now page /two renders.
- Click Browser Back and page changes to /, but page /one renders.
- etc.
Am i doinng something wrong here?
Issue Analytics
- State:
- Created 6 years ago
- Comments:20 (8 by maintainers)
Top Results From Across the Web
Keep browser URL in sync with application status
1. I have found no way to do this in Angular ·.route(url) will reload the page ·.url(url) will reload the page ·.go(..) will...
Read more >React Router DOM: How to handle routing in web apps
Let's say we encounter a nonexistent route/path in our app. Instead of letting the browser show an error, we can customize a 404...
Read more >React Router v5: The Complete Guide - SitePoint
Routing is the process of keeping the browser URL in sync with what's being rendered on the page. React Router lets you handle...
Read more >The Most Complete Guide for React Navigation - CopyCat Blog
Whenever you want to use URL in your application, routing comes into play. In this tutorial, we will explore routing or React navigation....
Read more >Tutorial v6.6.1 - React Router
And with that, we're ready to get started! ... Open it up and we'll put React Router on the page. Create and render...
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Ok after more investigating it looks like a react-router problem, but not with the switch - with the
Route
component update. The Route component uses context to get the current location, and I think theshouldComponentUpdate
of the mobx-reactobserver
component (which wraps App in your example) is returning false. This in turn is messing up the context update.Context is known to be a fairly broken feature, especially when pairing with MobX/Redux, which overwrite
shouldComponentUpdate
in places.This needs bringing up with the
react-router
guys.In terms of a workaround - wrapping
App
(the component which uses mobxobserver
) inwithRouter
from react-router works for me, as this will overwrite theshouldComponentUpdate
from observer.Sory about bring this discussion again, turns out that i’ve discovered a problem that i had im my configuration and this may help someone!
Once you create the History with synced Store, you don’t need the React Router
<BrowserRouter>
componentYou just initialize with
<Router history={History}>
and you’re ready to register and access your routes. My problem was caused by a duplicated initialization of the BrowserRouter in the startup React component:I had
<Router={history}>
and also<BrowserRouter>
, together only the last one was working and it was breaking the plugin functionality. After removingBrowserRouter
with only<Router history={History}>
solved my issue!Was a silly mistake because once you learn how to configure V4 routing and you plug this package into your app everything works fine, but turns out that two Routing are trying to control the app state and just the last one work breaking the package functionality.
Well, at the end just removing
BrowserRouter
and let the plugin do his job withsyncHistoryWithStore
solved my issues! Thanks.