history.push reloads the whole page even though the pathname is the same when using code-splitting

Viewed 769

My initial question was

How to add url params without the whole page reloading?

@Ajeet Shah told me in the comments that the page shouldn't reload if the pathname is the same. So I figured the problem lies elsewhere. I could pin point the problem and found out it has to do with code splitting, I could even create a reproducible example here.

The problem is the following: When part of the code is loaded asynchronously and it contains routes, calls to history.push() with the exact same pathname make the page reload.

example.js

import React from "react";
import { BrowserRouter as Router, Switch, Route, Link } from "react-router-dom";
import AsyncComponent from "./components/AsyncComponent";

export default function BasicExample() {
  return (
    <Router>
      <div>
        <ul>
          <li>
            <Link to="/">Home</Link>
          </li>
          <li>
            <Link to="/about/test">About</Link>
          </li>
        </ul>

        <hr />

        <Switch>
          <Route exact path="/">
            <Home />
          </Route>
          <Route path="/about">
            <AsyncComponent />
          </Route>
        </Switch>
      </div>
    </Router>
  );
}

function Home() {
  return (
    <div>
      <h2>Home</h2>
    </div>
  );
}

AsyncComponent.jsx

import React, { Suspense } from "react";

const Component = React.lazy(() => import("./Routes"));

export const AsyncComponent = (props) => {
  return (
    <Suspense fallback={<div>...loading</div>}>
      <Component />
    </Suspense>
  );
};

export default AsyncComponent;

Routes.jsx

import React, { useEffect } from "react";
import { Switch, Route } from "react-router-dom";
import { useRouteMatch } from "react-router";
import About from "./About";

export const Routes = (props) => {
  let { path } = useRouteMatch();
  console.log("rendering Routes");

  useEffect(() => {
    console.log("mounting Routes");
  }, []);

  return (
    <Switch>
      <Route exact path={`${path}/test`}>
        <About />
      </Route>
    </Switch>
  );
};

export default Routes;

About.jsx

import React, { useEffect } from "react";
import { useHistory } from "react-router";
import { Link } from "react-router-dom";

export const About = () => {
  console.log("rendering About");

  useEffect(() => {
    console.log("mounting About");
  }, []);

  const h = useHistory();

  return (
    <div>
      <Link
        to={{
          pathname: "/about/test",
          search: "foo=1&bar=2"
        }}
      >
        Push search params to About
      </Link>

      <button
        onClick={() => {
          h.push({
            pathname: "/about/test",
            search: "foo=1&bar=2"
          });
        }}
      >
        Push search params to About
      </button>

      <h2>About</h2>
    </div>
  );
};

export default About;

What am I doing wrong? Is there a way to avoid this while keeping code-splitting?

0 Answers
Related