React Router v6 useNavigate() doesn't navigate if replacing last element in path

Viewed 27716

I have a react component with the following function

    const handleNavigate = (clientId) => {
        console.log(clientId)
        navigate(`/dashboard/clients/${clientId}`)
    }

The console.log() is showing the ID I want to append to use in the navigate function.
AND
The URL in the browser is updating.

But the page does not change.

This works to navigate from /dashboard/clients to /dashboard/clients/foo

but it does not work to navigate from /dashboard/clients/foo to /dashboard/clients/bar

The clientId is passed into the card like so...

const CompanyCard = (props) => {
    const { client, showWatchlist, removeDisabled, showRemove, removeType } = props
...
}

then in the card

                <CardActionArea
                    onClick={() => handleNavigate(client._id)}
                 ...

Any ideas?
Thanks

UPDATE

After reading up from @redapollos suggestion I tried Outlet and the

useRoutes methods... neither worked.

import { useRoutes } from 'react-router-dom'

// then in the routes...

        { path: 'clientdetail/:id', element: <ClientDetail /> },
        { path: 'clientdetail/', element: <ClientDetail /> },

This might be due to using the useRoutes hook but I am still working on it.

Another question here on SO that might get an answer sooner - https://stackoverflow.com/a/70009104/13078911

9 Answers

Workable solution!

navigate('/url')
navigate(0)

After replacing the url, manually calling navigate(0) will refresh the page automatically!

This will work in a situation like navigate from /same_path/foo to /same_path/bar.

Be aware of unintended page referesh behavior:

For a normal situation like navigate from /home to /same_path/bar, navigate(0) will cause page to refresh even after page has finished rendering. And to prevent that, you can take a look at this question.

More info:

  1. useNavigate docs

  2. How do I reload a page with react-router?

Try replacing the URL instead of adding a new one. when you are going from /dashboard/clients to /dashboard/clients/foo you are going from a parent to a child, your URL has everything plus /foo. But, when you are going from /dashboard/clients/foo to /dashboard/clients/bar you are navigating to a sibling /foo to /bar that might be causing the issue. try to replace the value like navigate(/dashboard/clients/ba, {replace: true}) here is example of how to use this in general. use it for more information. https://www.digitalocean.com/community/tutorials/react-react-router-v6

I had this same issue and my code was fine, however, I found out at this post that optional params aren't supported in v6.
https://github.com/remix-run/react-router/issues/7285

I had:

<Routes>
  <Route path="list/:id?" element={<SystemList />} />
</Routes>

and had to change it to:

<Routes>
  <Route path="list/:id" element={<SystemList />} />
  <Route path="list/" element={<SystemList />} />
</Routes>

I'm hoping they support it in the future but as of v6.0.2 they do not.

I just read in React Router Dom Docs v6 this solution:

import { useNavigate } from 'react-router-dom';
...
const navigate = useNavigate();
...
<Button onClick={() => navigate('../user', { replace: true })}>Register</Button>

So, basically I added ../ before the route and the replace: true.
Reference: https://reactrouter.com/docs/en/v6/hooks/use-navigate

It worked for me, hope it works for u! (:

Maybe try the component Navigate:

<Navigate to={<your_path>}/>

This might be a little late but I had the same issue and you simply just have to trigger a re-render for your component. You can do this by adding a useEffect hook within your component you have assigned /dashboard/clients/:clientId to with a dependency of the param you want to update.

It should look something like this:

import React, { useEffect } from 'react'
import { useParams, useNavigate } from 'react-router-dom';


const ClientDashboard = () => {

    const params = useParams()
    const navigate = useNavigate()

    useEffect(() => {
    //do something with new id 
    },[params.clientId])

    const handleNavigate = (clientId) => {
        navigate(`/dashboard/clients/${clientId}`)
    }

    .....
}

Your page should now update with the new param

I think this is a better work around on this one.

import React from 'react' 
import { useHistory } from 'react-router-dom' 
... 

const history = useHistory() 
const handleNavigate = (clientId) => {
        console.log(clientId)
        history.push(`/dashboard/clients/${clientId}`)
    }

Make sure your app is wrapped in a BrowserRouter from react-router-dom

Try adding window-location as key prop to the element in route

ie

<Route path=":id" element={ <Hello key={window.location.pathname} } />

Based on this link https://github.com/remix-run/react-router/issues/8245 I could solve this issue.

I guess that as nothing has been changed the screen is not updated. As soon as I added I useEffect on the target route component and passed the lastelement as a parameter it worked.

In other words: On the target component add: Reac.useEffect(....) [lastElement].

Related