Forcing a React-Router <Link> to load a page, even if we're already on that page

React Router

React Router Problem Overview


Is there a way to force a React-Router <Link> to load a page from path, even when the current location is already that page? I can't seem to find any mention of this in the react-router documentations.

We have a page on a route for "apply" that loads up a landing page with a hero image, some explanatory text, etc., and an "apply for this program" button that swaps in content that acts as an application form. This all happens on the same "apply" route, because users should not be able to directly navigate to this form without first hitting the landing page.

However, when they have this form open, and they click on the apply link in the nav menu again, the entire page should reload as it would on first mount, getting them "back" (but really, forward) to the landing page again.

Instead, clicking the <Link> does nothing, because react-router sees we're already on the "apply" page, and so does not unmount the current page to then mount a different one.

Is there a way to force it to unmount the current page before then mounting the requested page, even if it's for the page users are supposedly already on? (via a <Link> property for instance?)

React Router Solutions


Solution 1 - React Router

In the Route component, specify a random key.

<Route path={YOURPATH} render={(props) => <YourComp {...props} keyProp={someValue} key={randomGen()}/>} />

when react see a different key, they will trigger rerender.

Solution 2 - React Router

A fix I used to solve my little need around this was to change the location that React-Router looks at. If it sees a location that we're already on (as in your example) it won't do anything, but by using a location object and changing that, rather than using a plain string path, React-Router will "navigate" to the new location, even if the path looks the same.

You can do this by setting a key that's different from the current key (similar to how React's render relies on key) with a state property that allows you to write clear code around what you wanted to do:

render() {
  const linkTarget = {
    pathname: "/page",
    key: uuid(), // we could use Math.random, but that's not guaranteed unique.
    state: {
      applied: true
    }
  };

  return (
    ...
    <Link to={linkTarget}>Page</Link>
    ...
  );
}

Note that (confusingly) you tell the Link which values you need pass as a state object, but the link will pass those values on into the component as props. So don't make the mistake of trying to access this.state in the target component!

We can then check for this in the target component's componentDidUpdate like so:

componentDidUpdate(prevProps, prevState, snapshot) {
  // Check to see if the "applied" flag got changed (NOT just "set")
  if (this.props.location.state.applied && !prevProps.location.state.applied) {
    // Do stuff here 
  }
}

Solution 3 - React Router

Simple as:

<Route path="/my/path" render={(props) => <MyComp {...props} key={Date.now()}/>} />

Works fine for me. When targeting to the same path:

this.props.history.push("/my/path");

The page gets reloaded, even if I'm already at /my/path.

Solution 4 - React Router

Not a good solution because it forces a full page refresh and throws an error, but you can call forceUpdate() using an onClick handler like:

<Link onClick={this.forceUpdate} to={'/the-page'}>
    Click Me
</Link>

All I can say is it works. I'm stuck in a similar issue myself and hope someone else has a better answer!

https://stackoverflow.com/questions/38809989/react-router-link-not-causing-component-to-update-within-nested-routes

Solution 5 - React Router

This might be a common problem and I was looking for a decent solution to have in my toolbet for next time. React-Router provides some mechanisms to know when an user tries to visit any page even the one they are already.

Reading the location.key hash, it's the perfect approach as it changes every-time the user try to navigate between any page.

componentDidUpdate (prevProps) {
    if (prevProps.location.key !== this.props.location.key) {
        this.setState({
            isFormSubmitted: false,
        })
    }
}

After setting a new state, the render method is called. In the example, I set the state to default values.

Reference: A location object is never mutated so you can use it in the lifecycle hooks to determine when navigation happens

Solution 6 - React Router

I solved this by pushing a new route into history, then replacing that route with the current route (or the route you want to refresh). This will trigger react-router to "reload" the route without refreshing the entire page.

<Link onClick={this.reloadRoute()} to={'/route-to-refresh'}>
    Click Me
</Link>

let reloadRoute = () => {
    router.push({ pathname: '/empty' });
    router.replace({ pathname: '/route-to-refresh' });
}

React router works by using your browser history to navigate without reloading the entire page. If you force a route into the history react router will detect this and reload the route. It is important to replace the empty route so that your back button does not take you to the empty route after you push it in.

According to react-router it looks like the react router library does not support this functionality and probably never will, so you have to force the refresh in a hacky way.

Solution 7 - React Router

I found a simple solution.

<BrowserRouter forceRefresh />

This forces a refresh when any links are clicked on. Unfortunately, it is global, so you can't specify which links/pages to refresh only.

From the documentation:

> If true the router will use full page refreshes on page navigation. You may want to use this to imitate the way a traditional server-rendered app would work with full page refreshes between page navigation.

Solution 8 - React Router

I got this working in a slightly different way that @peiti-li's answer, in react-router-dom v5.1.2, because in my case, my page got stuck in an infinite render loop after attempting their solution.

Following is what I did.

<Route
  path="/mypath"
  render={(props) => <MyComponent key={props.location.key} />}
/>

Every time a route change happens, the location.key prop changes even if the user is on the same route already. According to react-router-dom docs:

> Instead of having a new React element created for you using the > component prop, you can pass in a function to be called when the > location matches. The render prop function has access to all the same > route props (match, location and history) as the component render > prop.

This means that we can use the props.location.key to obtain the changing key when a route change happens. Passing this to the component will make the component re-render every time the key changes.

Solution 9 - React Router

Here's a hacky solution that doesn't require updating any downstream components or updating a lot of routes. I really dislike it as I feel like there should be something in react-router that handles this for me.

Basically, if the link is for the current page then on click...

  1. Wait until after the current execution.
  2. Replace the history with /refresh?url=<your url to refresh>.
  3. Have your switch listen for a /refresh route, then have it redirect back to the url specified in the url query parameter.

Code

First in my link component:

function MenuLink({ to, children }) {
    const location = useLocation();
    const history = useHistory();
    const isCurrentPage = () => location.pathname === to;
    const handler = isCurrentPage() ? () => {
        setTimeout(() => {
            if (isCurrentPage()) {
                history.replace("/refresh?url=" + encodeURIComponent(to))
            }
        }, 0);
    } : undefined;

    return <Link to={to} onClick={handler}>{children}</Link>;
}

Then in my switch:

<Switch>
        <Route path="/refresh" render={() => <Redirect to={parseQueryString().url ?? "/"} />} />
        {/* ...rest of routes go here... */}
<Switch>

...where parseQueryString() is a function I wrote for getting the query parameters.

Solution 10 - React Router

Solved using the Rachita Bansal answer but with the componentDidUpdate instead componentWillReceiveProps

componentDidUpdate(prevProps) {
    if (prevProps.location.pathname !== this.props.location.pathname) { window.location.reload();
    }
}

Solution 11 - React Router

You can use the lifecycle method - componentWillReceiveProps When you click on the link, the key of the location props is updated. So, you can do a workaround, something like below,

/**
 * @param {object} nextProps new properties
 */
    componentWillReceiveProps = (nextProps)=> {
        if (nextProps.location.pathname !== this.props.location.pathname) {
            window.location.reload();
        }
    };

Solution 12 - React Router

To be honest, none of these are really "thinking React". For those that land on this question, a better alternative that accomplishes the same task is to use component state.

Set the state on the routed component to a boolean or something that you can track:

this.state = {
    isLandingPage: true // or some other tracking value
};

When you want to go to the next route, just update the state and have your render method load in the desired component.

Solution 13 - React Router

Try just using an anchor tag a href link. Use target="_self" in the tag to force the page to rerender fully.

Solution 14 - React Router

i was with the same issue and i resolved by using a href instead of Link

<a href='/'>

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMike &#39;Pomax&#39; KamermansView Question on Stackoverflow
Solution 1 - React RouterPeiti LiView Answer on Stackoverflow
Solution 2 - React RouterflashView Answer on Stackoverflow
Solution 3 - React RouterMendesView Answer on Stackoverflow
Solution 4 - React Routerunleash.itView Answer on Stackoverflow
Solution 5 - React RouterCarlos BensantView Answer on Stackoverflow
Solution 6 - React RouterZach TaylorView Answer on Stackoverflow
Solution 7 - React RouterChrisH.View Answer on Stackoverflow
Solution 8 - React RouterDeepalView Answer on Stackoverflow
Solution 9 - React RouterDavid SherretView Answer on Stackoverflow
Solution 10 - React Routerjogle05View Answer on Stackoverflow
Solution 11 - React RouterRachita BansalView Answer on Stackoverflow
Solution 12 - React RouterdbarthView Answer on Stackoverflow
Solution 13 - React RouterRAMView Answer on Stackoverflow
Solution 14 - React RouterAndre LopesView Answer on Stackoverflow