When I’m on “/home” then I click “/about” multiple times, then when I click back, it doesn’t go back to “/home”. Instead, there are many duplicate “/about” that I need to click back.
I have checked the github issue of React Router (here), but couldn’t find a clear solution, and everything seems so confusing.
Can anyone help please?
Hello!
You can add the hook shown at the bottom of the github issue page to each of your components that need to be routed or to the <Switch>
(sample project):
LocationBlocker.js
import { useEffect } from "react";
import { useHistory } from "react-router-dom";
export default function useLocationBlocker() {
const history = useHistory();
useEffect(
() => {
history.block(
(location, action) =>
action !== "PUSH" ||
getLocationId(location) !== getLocationId(history.location)
);
},
[] // eslint-disable-line react-hooks/exhaustive-deps
);
}
function getLocationId({ pathname, search, hash }) {
return pathname + (search ? "?" + search : "") + (hash ? "#" + hash : "");
}
Routes.jsx
import Contact from './Contact';
import About from './About';
import useLocationBlocker from "./LocationBlocker";
export default function Routes() {
useLocationBlocker();
return (
<Switch>
<Route path="/about">
<About />
</Route>
<Route path="/contact">
<Contact />
</Route>
<Route path="/">
<h2>Home</h2>
</Route>
</Switch>
);
}
Then, inside your BrowserRouter
:
<BrowserRouter>
<nav>
<Link to="/">Home</Link>
<Link to="/about">About</Link>
</nav>
<Routes />
</BrowserRouter>
I’m not an expert, so there may be another, better/shorter, way of writing this code.
Anyway, I hope it helps ,
Regards!
2 Likes
Thanks mate for your reply! But I cannot import useHistory
.
It always show this error: 'react-router-dom' does not contain an export named 'useHistory'.
I’ve searched on the internet and found that the react-router-dom version 6.0.0 does not have it. But my react-router-dom is just version 4.3.1 but still it don’t work. Maybe that is a bug from the library??
Oh, yeah! I didn’t take into account the library version; I just assumed it was the latest.
Anyway, glad you solved it .
I have a small doubt @skaparate! Just to clarify, does useEffect(…) work like componentDidMount() which was only called once when the Routes component mounted.
If I do history.block(…) without using useEffect(…), is that fine? because I see it works as well.
Yes! In fact, if you wanted to use purely functional react, that’s one way to achieve similar componentDidMount
functionality you get with classes.
1 Like
So do you think it is fine to do history.block(...)
without useEffect(...)
?
I tried it in Routes
component (functional component), and when I do console.log
, it only calls the function that creates Routes
once . So maybe it calls history.block(...)
only once too which means I may not need to useEffect()
Yes, it’s fine. Actually, if you read the last comment on the issue you posted, the proposed solution is to use history
directly
Scratch that. I was wrong. I was confused with the answers .
You can use history directly as shown here:
function applyBrowserLocationBlocker(history: History) {
let currentLocation = null
history.block((location, action) => {
const nextLocation = location.pathname + location.search
if (action === 'PUSH') {
if (currentLocation === nextLocation) {
return false
}
}
currentLocation = nextLocation
})
}
The code of my previous answer uses this function as an effect
in react.
1 Like
Thank you very much, mate!! You’ve been very helpful. I’m very grateful . It’s nice to meet you.
1 Like