molefrog / molefrog/wouter

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

Open
#506 8 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
7.9k
Forks
190
Avg merge
12h 50m
Merged PRs (30d)
3

Description

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

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Begin with the linked CodeSandbox reproduction and compare navigation after a promise with immediate navigation. Check the behavior against the React 18 createRoot comparison mentioned in the issue. Done means navigating from /route-a to /route-b after a promise does not re-render PageA with the destination pathname, while the existing route transition still works.

Written by the indexing model from the issue text.

Assessment

Tech stack
react, typescript
Domain
frontend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.