When using a HashRouter
, and within a component using useLocation
, there is a discrepancy between the window.location
object and the location
object from useLocation
.
As I am writing this I have noticed there may be a confusion around what useLocation
is actually pointing to. The pathname
from useLocation
seems to actually be the window.location.hash
without the #
. But the hash
seems to not be pointing at anything at all.
Honestly I wasn't sure if I should've posted this as an issue on react-routers Github, but I wanted to post this here in case there is some fundamental piece of info I'm missing about how useLocation
is supposed to work (more importantly in relation to what router you are using).
Does useLocation
behave differently when you wrap it in <BrowserRouter>
vs <HashRouter>
vs <MemoryRouter>
etc.?
Values from window.location
:
{
pathname: "/myPage/"
hash: "#/testpath/123"
search: ""
}
Values from location = useLocation()
:
{
pathname: "/testpath/123"
hash: ""
search: ""
key: "abc123"
state: null
}
When using a
HashRouter
, and within a component usinguseLocation
, there is a discrepancy between thewindow.location
object and thelocation
object fromuseLocation
.As I am writing this I have noticed there may be a confusion around what
useLocation
is actually pointing to. Thepathname
fromuseLocation
seems to actually be thewindow.location.hash
without the #. But the hash seems to not be pointing at anything at all.
The HashRouter
router uses the path defined after the first hash of the URL.
For example, given:
<Route path="/testpath/123" element={....} />
"https://..../#/testpath/123"
The location
returned from the useLocation
hook may look like:
{
"pathname": "/testpath/123",
"search": "",
"hash": "",
"state": null,
"key": "ff78cgdt"
}
As compared to window.location
{
"ancestorOrigins": {
"0": "https://...."
},
"href": "https://..../#/testpath/123",
"origin": "https://....",
"protocol": "https:",
"host": "....",
"hostname": "....",
"port": "",
"pathname": "/",
"search": "",
"hash": "#/testpath/123"
}
Given:
<Route path="/testpath/123" element={....} />
"https://..../#/testpath/123#foo"
Then the location
object would look like:
{
"pathname": "/testpath/123",
"search": "",
"hash": "#foo",
"state": null,
"key": "r7bfxju4"
}
{
"ancestorOrigins": {
"0": "https://...."
},
"href": "https://..../#/testpath/123#foo",
"origin": "https://....",
"protocol": "https:",
"host": "....",
"hostname": "....",
"port": "",
"pathname": "/",
"search": "",
"hash": "#/testpath/123#foo"
}
Notice the only difference now is that the "foo"
is now part of the location
object, the "hash" of the route path the app's router is using. It also is included in the hash of window.location
, e.g. everything after the first hash.
Does
useLocation
behave differently when you wrap it in<BrowserRouter>
vs<HashRouter>
vs<MemoryRouter>
etc.?
No, not really. These routers all manage and/or maintain their own internal history object and state, e.g. what location
is in each context. The BrowserRouter
couples internal routing/navigation actions to a browser's DOM, and similarly the HashRouter
uses just the hash of what is effectively a static location, e.g. an app hosted/served from a specific directory on a server. The MemoryRouter
is intended to be used in non-DOM environments, e.g. Node environments like Jest testing, etc.
Depending on which router you use, and what the URL path/etc value is, some of the location
properties may not be set, but the useLocation
hook and location
object is basically the same regardless.
I don't believe there is a bug or issue to file here as everything you described seems like reasonable behavior given the HashRouter
and the console logging you used.