Skip to content

Re-rendering the component for a source route after navigating to a destination route in a promise #506

@elanmed

Description

@elanmed

Issue

When navigating from a source route (i.e. /route-a) to a destination route (/route-b) after a promise, the component for the source route is re-rendered after the navigation - when the URL is already set to the destination.

Reproducing

I was able to reproduce this issue in a code sandbox: https://codesandbox.io/p/sandbox/exciting-wilson-l9sk9x

export default function App() {
  return (
    <Router>
      <Switch>
        <Route path="/" component={Root} />
        <Route path="/route-a" component={PageA} />
        <Route path="/route-b" component={PageB} />
      </Switch>
    </Router>
  );
}

function PageA() {
  console.log("PageA render, pathname:", window.location.pathname);
  return (
    <div>
      <p>page A</p>
      <button
        onClick={() => {
          Promise.resolve().then(() => {
            navigate("/route-b");
          });
        }}
      >
        navigate after promise
      </button>
      <button
        onClick={() => {
          navigate("/route-b");
        }}
      >
        navigate immediately
      </button>
    </div>
  );
}

function PageB() {
  return <div>page B</div>;
}

function Root() {
  return (
    <div>
      <h1>Steps to repro</h1>
      ...
    </div>
  );
}
  • Go to /route-a
  • Open the console
  • Click navigate after promise

The console will read:

PageA render, pathname: /route-a
PageA render, pathname: /route-b

This is unexpected, since PageA should only render on /route-a, not /route-b

If you repro with the following steps, the extra render does not occur:

  • Go to /route-a
  • Open the console
  • Click navigate immediately

The console will only read:

PageA render, pathname: /route-a

Which is what I would expect in both cases.

Why this is an issue

Say I have a condition in PageA to check for a search param (i.e. auth=1), and if it does not exist, navigate to an earlier route where the search param is populated. When navigating from /route-a to /route-b, I don't include the search param i.e. I would navigate from /route-a?auth=1 to /route-b , not /route-b?auth=1. When navigating after promise, PageA is re-rendered with the URL of /route-b. Since the auth=1 search param is not present, my condition kicks in, and I'm navigated away from the destination route. This is more or less the scenario that led me to root-cause this issue.

Notes

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions