Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React Router - How to Determine If Back button was hit?

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.

like image 423
chobo2 Avatar asked Jan 25 '17 22:01

chobo2


People also ask

How do you know when a route changes in react?

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]); //... };

How do you handle the browser Back button in react v6 router?

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 }); );


2 Answers

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;
like image 174
Proustibat Avatar answered Oct 04 '22 09:10

Proustibat


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
         );
     }
 }
like image 38
Gasim Avatar answered Oct 04 '22 09:10

Gasim