Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Link component update browser history when location is the same

I used react router v 4.3.1 When i click on home page link many times, each click creates a new history item. Home page is re-rendered every time. Now your browser navigation is broken (back/forward buttons are not working as expected).

import React from 'react';
import { render } from 'react-dom';
import { BrowserRouter as Router, Route, Link } from 'react-router-dom';

const Example = () => (
  <Router>
    <div>
      <ul>
        <li><Link to="/">Home</Link></li> 
        <li><Link to="/">Home 1</Link></li>
        <li><Link to="/">Home 2</Link></li>
        <li><Link to="/about">About</Link></li>
        <li><Link to="/topics">Topics</Link></li>
      </ul>

      <hr />

      <Route exact path="/" render={()=><p>Home</p>} />
      <Route path="/about" render={()=><p>about</p>} />
      <Route path="/topics" render={()=><p>topics</p>} />
    </div>
  </Router>
);

render(<Example />, document.body);

Help, how to fix this?

like image 821
Vadim Hulevich Avatar asked Dec 04 '25 10:12

Vadim Hulevich


1 Answers

It's an old and known issue introduced with React Router v4 and it's currently (AFAIK) unsolved.

Fortunately it's pretty easy to workaround using a custom history object (something you would do also if you want to keep in sync Redux state with the browser history). True production code should be more robust than what I'm writing here but you can start with this:

a) First of all use <Router> instead of <BrowserRouter>.

import { Router, Route, Link } from "react-router-dom";

b) Creates your own history object (be sure to npm add history if you didn't):

import createBrowserHistoryfrom "history/createBrowserHistory";

// ...

const history = createBrowserHistory();

c) Replace the push() method with your own implementation:

const originalHistoryPush = history.push;

history.push = function(path, state = {}) {
    if (!this.location) {
        originalHistoryPush(path, state);
        return;
    }

    const oldPath = this.location.pathname + this.location.search + this.location.hash;
    if (oldPath !== path || !shallowEqual(state, this.location.state)) {
        originalHistoryPush(path, state);
    } else {
        this.replace(path, state);
    }
};

d) Use the custom history:

<Router history={history}>...</Router>

Note that I'm using an hypothetical shallowEqual() method for comparison. You can quickly write your own or pick one of the many implementations out there.

like image 169
Adriano Repetti Avatar answered Dec 06 '25 00:12

Adriano Repetti



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!