9

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/router@1.2.1 (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;
Tom
  • 1,914
  • 1
  • 18
  • 30
  • 2
    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. – aver Feb 13 '20 at 00:41

4 Answers4

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

Kafkalasch
  • 35
  • 5
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>
}
Opan
  • 29
  • 3
1

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;
};
Kizmar
  • 1,987
  • 2
  • 15
  • 23
0

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

import { navigate } from 'gatsby'