wouter icon indicating copy to clipboard operation
wouter copied to clipboard

[BUG] `useHashLocation` not syncing with state

Open martonlederer opened this issue 1 year ago • 4 comments

With the useHashLocation hook, the active route does not sync with the current state/location, once it is updated. The initial location loads the correct route.

For example/reproduction:

  1. Set up a project with wouter and hash routing.
  2. Create a route, let's call it test. Add a link from it to the index (#/) or a navigate() call (using useLocation)
  3. Go to a #/test
  4. Click the link you added. The location will be updated, but the active route will not change.

martonlederer avatar Feb 21 '24 18:02 martonlederer

Hi! I can't reproduce this, would you mind sharing your code?

molefrog avatar Feb 22 '24 10:02 molefrog

Hey! Yeah so it is really simple, just a home page and an App component:

export default function App() {
	return (
		<>
			<Nav />
			<main>
				<Router hook={useHashLocation}>
                    <Switch>
                       <Route path="/config" component={Config} />
                       <Route path="/" component={Home} />
                    </Switch>
                  </Router>
			</main>
		</>
	);
}

martonlederer avatar Feb 23 '24 20:02 martonlederer

Does your link look like <Link href="/" /> or <Link href="#/" />?

molefrog avatar Feb 26 '24 09:02 molefrog

Hello — I think I stumbled on this issue today and can share a reproduction.

Here's a replit link that has runnable code: https://replit.com/@neoeno/Reproduction-of-wouter-active-links-issue-with-hash-location

An example of how it looks in the browser:

https://github.com/molefrog/wouter/assets/1007202/0a75aaaf-dd43-4e7c-a561-9417cba3148e

And here's the relevant code:

// App.jsx

import "./App.css";
import { Route, Router, Link } from "wouter";
import { useHashLocation } from "wouter/use-hash-location";

export default function App() {
  return (
    <>
      <h1>Default useBrowserLocation activates the links</h1>
      <Router>
        <ul>
          <li>
            <Link
              href="/route-one"
              className={(active) => (active ? "active" : "normal")}
            >
              Link to Route One
            </Link>
          </li>
          <li>
            <Link
              href="/route-two"
              className={(active) => (active ? "active" : "normal")}
            >
              Link to Route Two
            </Link>
          </li>
        </ul>
        <Route path="/route-one">
          <p>Route One</p>
        </Route>
        <Route path="/route-two">
          <p>Route Two</p>
        </Route>
      </Router>

      <h1>useHashLocation does not activate the links</h1>
      <Router hook={useHashLocation}>
        <ul>
          <li>
            <Link
              href="/route-one"
              className={(active) => (active ? "active" : "normal")}
            >
              Link to Route One
            </Link>
          </li>
          <li>
            <Link
              href="/route-two"
              className={(active) => (active ? "active" : "normal")}
            >
              Link to Route Two
            </Link>
          </li>
        </ul>
        <Route path="/route-one">
          <p>Route One</p>
        </Route>
        <Route path="/route-two">
          <p>Route Two</p>
        </Route>
      </Router>
    </>
  );
}
/* App.css */

.active {
  border: 1px solid red;
}

I believe the issue occurs here: https://github.com/molefrog/wouter/blob/v3/packages/wouter/src/index.js#L239

  return asChild && isValidElement(children)
    ? cloneElement(children, { onClick, href })
    : h("a", {
        ...restProps,
        onClick,
        href,
        // `className` can be a function to apply the class if this link is active
        className: cls?.call ? cls(path === href) : cls, // <------
        children,
        ref,
      });

From debugging, href ends up having the #, while path does not. Could be related to #421?

Thanks for all your hard work on wouter! Please do say if you'd appreciate a PR to fix.

neoeno avatar May 07 '24 16:05 neoeno

hi @neoeno, this is indeed a bug. the href gets transformed using the hrefs() function a few lines above. so I guess we need to keep the original href and store the transformed one somewhere else. feel free to file a PR 💁‍♂️

molefrog avatar May 09 '24 06:05 molefrog