Reach router navigate updates URL but not component
Asked Answered
J

5

10

I'm trying to get Reach Router to navigate programmatically from one of my components. The URL is updated as expected however the route is not rendered and if I look at the React developer tools I can see the original component is listed as being displayed.

If I refresh the page once at the new URL then it renders correctly.

How can I get it to render the new route?

A simplified example is shown below and I'm using @reach/[email protected] (it may also be salient that I'm using Redux).

import React from 'react';

import { navigate } from '@reach/router';

const ExampleComponent = props => {
  navigate('/a/different/url');

  return <div />;
};

export default ExampleComponent;
Jelks answered 27/8, 2019 at 15:36 Comment(1)
Hi, have you figured out what was causing this? I am running into same issue regardless of navigate or Link being used. If I refresh the page, then the component renders.Tham
B
2

I was running into the same issue with a <NotFound defualt /> route component.

This would change the URL, but React itself didn't change:

import React from "react";
import { RouteComponentProps, navigate } from "@reach/router";

interface INotFoundProps extends RouteComponentProps {}

export const NotFound: React.FC<INotFoundProps> = props => {
  // For that it's worth, neither of these worked 
  // as I would have expected
  if (props.navigate !== undefined) {
    props.navigate("/");
  }
  // ...or...
  navigate("/", { replace: true });

  return null;
};

This changes the URL and renders the new route as I would expect:

...
export const NotFound: React.FC<INotFoundProps> = props => {
  React.useEffect(() => {
    navigate("/", { replace: true });
  }, []);

  return null;
};
Barratry answered 11/10, 2019 at 14:13 Comment(0)
M
2

Could it be that you use @reach/router in combination with redux-first-history? Because I had the same issue and could solve it with the following configuration of my historyContext:

import { globalHistory } from "@reach/router";
// other imports

const historyContext = createReduxHistoryContext({
   // your options...
   reachGlobalHistory: globalHistory // <-- this option is the important one that fixed my issue
}

More on this in the README of redux-first-history

Macrobiotics answered 29/5, 2020 at 9:27 Comment(0)
S
2

The same issue happens to me when I'm just starting to play around with Reach Router. Luckily, found the solution not long after.

Inside Reach Router documentation for navigate, it is stated that:

Navigate returns a promise so you can await it. It resolves after React is completely finished rendering the next screen, even with React Suspense.

Hence, use await navigate() work it for me.

import React, {useEffect} from 'react';
import {useStoreState} from "easy-peasy";
import {useNavigate} from "@reach/router";

export default function Home() {
    const {isAuthenticated} = useStoreState(state => state.auth)
    const navigate = useNavigate()

    useEffect(()=> {
        async function navigateToLogin() {
            await navigate('login')
        }
        if (!isAuthenticated) {
            navigateToLogin()
        }
    },[navigate,isAuthenticated])

    return <div>Home page</div>
}
Staff answered 30/7, 2020 at 7:3 Comment(0)
B
1

If you use <React.StrictMode>, remove it and it should work.

Brunhilda answered 25/5, 2023 at 19:56 Comment(0)
D
-1

Try and use gatsby navigate. It uses reach-router. It solved my problem.

import { navigate } from 'gatsby'
Dogma answered 2/4, 2021 at 20:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.