I have these scenarios
Settings Page -> Results Page -> Details Page
User chooses settings, clicks next, gets results and then clicks into more details.
Details Page -> Results Page
User goes back to Results page from Details Page. This causes a full re-render, causing me to hit the server again for no point(I have the results stored in an array).
Details Page -> Results Page -> Settings Page -> Results Page
The user goes to details, then back to results(want to grab stored results), then goes back to settings page, makes changes and then goes back to results page(now I want a full grab from server again).
I am wondering if there is away in react router to determine if I came to the page via the browser history or if I was going in a forward motion.
To detect route change with React Router, we can use the useLocation hook. import { useEffect } from "react"; import { useLocation } from "react-router-dom"; const SomeComponent = () => { const location = useLocation(); useEffect(() => { console. log("Location changed"); }, [location]); //... };
Usage: import { useNavigate } from 'react-router-dom'; import { useBackListener } from '../path/to/useBackListener'; ... const navigate = useNavigate(); useBackListener(({ location }) => console. log("Navigated Back", { location }); navigate("/", { replace: true }); );
I was looking for the same thing then I finally find a solution that seems simple.
Quick answer:
I use history.action
value to determine if the user is coming from a back button or from a classic navigation.
If history.action
is equal to 'POP'
then the back button has been hit. Otherwise it's 'PUSH'
.
Detailed answer:
I get access to history in props of each page because I do something like that:
<Provider store = { store }>
<AppRouter />
</Provider>
Where AppRouter
is:
import React from 'react';
import { Router, Route, Switch } from 'react-router-dom';
import createHistory from 'history/createBrowserHistory';
import PublicRoute from './PublicRoute';
import PageHome from '../pages/front/home/PageHome';
export const history = createHistory();
const AppRouter = () => (
<Router history={ history }>
<div>
<Switch>
<PublicRoute
exact = { true }
path = "/"
component = { PageHome }
history={ history }
/>
< ..... Other routes here ..... >
</Switch>
</div>
</Router>
);
export default AppRouter;
And PublicRoute
component is something like that:
import React from 'react';
import { Route } from 'react-router-dom';
import Header from '../components/header/Header';
const PublicRoute = ( { component: Component, ...rest } ) => (
<Route
component={ ( props ) => (
<div>
<Header />
<Component { ...props } />
</div>
)}
{ ...rest }
/>
);
export default PublicRoute;
In React Router, the component stays mounted if router calls for paths that are children of that component. So, in your example, you can do something like the following:
<Route path="items" component={Results}>
<Route path=":id" component={Detail} />
</Route>
This way, Results
component does not get unmounted when Detail
component is being mounted because Detail
is a child of Results
. However, if you do not want to see Results component getting rendered when you are in Detail, you can only render children when they exist. Something like the following:
class Results extends React.Component {
render() {
if (this.props.children) {
// This will enter Detail component
return this.props.children;
}
return (
// Render results component
);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With