[BUG] `useHashLocation` not syncing with state
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:
- Set up a project with wouter and hash routing.
- Create a route, let's call it
test. Add a link from it to the index (#/) or anavigate()call (usinguseLocation) - Go to a
#/test - Click the link you added. The location will be updated, but the active route will not change.
Hi! I can't reproduce this, would you mind sharing your code?
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>
</>
);
}
Does your link look like <Link href="/" /> or <Link href="#/" />?
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.
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 💁♂️