2

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?

jperl
  • 4,662
  • 2
  • 16
  • 29
  • Maybe do history.push only when you want to leave or rerender page, othervise just have search and query inside state that would change your queries and everything you need. – Lygis Mar 22 '21 at 16:20
  • 1
    Does this answer your question? [react-router: How do I update the url without causing a navigation/reload?](https://stackoverflow.com/questions/57101831/react-router-how-do-i-update-the-url-without-causing-a-navigation-reload) – Rohan Agarwal Mar 22 '21 at 16:20
  • No, I have seen this thread and it didn't answer my question. – jperl Mar 22 '21 at 16:21
  • @Lygis I would have liked to keep the params when going back and forth. – jperl Mar 22 '21 at 16:22
  • This applies to pagination as well. Say the user views the details of an item, I don't want the user to select the page again when going back. – jperl Mar 22 '21 at 16:27
  • It doesn't re-render the component when you do `history.push` (or `Link`) to same path. Here is a demo: https://codesandbox.io/s/react-router-basic-forked-u07et?file=/example.js Go to "About" and check console logs. – Ajeet Shah Mar 22 '21 at 16:36
  • Hmm, perhaps have your state inside of parent component, so it would not reset. – Lygis Mar 22 '21 at 16:39
  • Oh, I guess I must be doing something wrong then... I'm going to look into it. – jperl Mar 22 '21 at 16:39
  • @AjeetShah what could be the reason that history.push causes a reload even if the pathname is the same? – jperl Mar 22 '21 at 16:57
  • Or maybe Page isn't reloading. I mean, Component is not un-mounting and re-mounting. Something else in the component is triggering the APIs calls which makes you think the Page is Reloaded. I am guessing. – Ajeet Shah Mar 22 '21 at 17:27
  • I've looked into it and it seems that it is related to code-splitting. Removing the async part fixes the issue. I'll post an answer once I find a solution to my problem. – jperl Mar 22 '21 at 18:45
  • I edited my question and I added a link to a reproducible example. Thank you for helping me. – jperl Mar 22 '21 at 20:02

0 Answers0