react-router icon indicating copy to clipboard operation
react-router copied to clipboard

[Bug]: Redirecting synchronously/without flicker

Open mogelbrod opened this issue 2 years ago • 7 comments

Edit: This might actually be a feature request - I wasn't sure if it's supposed to be possible or not.

What version of React Router are you using?

[email protected]

Steps to Reproduce

  1. Open https://codesandbox.io/s/react-router-v6-redirect-flash-5plmi?file=/src/App.js
  2. Click on Two (or Three) in the header
  3. Click on Root in the header

Expected Behavior

The pages for Root, Two and Three are rendered immediately after clicking on their respective links.

Actual Behavior

Clicking on Root briefly renders nothing in the <Routes> block, followed by the correct content being shown shortly thereafter. This makes for a subpar experience.

I'm guessing this is due to <Navigate> triggering the redirect in an useEffect(). But I have not find any alternative ways to handle a redirect like this. react-router v3 had the onEnter callback prop for <Route> which solved this by deferring the re-render until the callback completed, including allowing the next route to be modified.

Relevant code:

<Routes>
  <Route index element={<Navigate replace to="one" />} />
</Routes>
...
<Link to="/" children="Root" />

mogelbrod avatar Nov 09 '21 14:11 mogelbrod

I wrote about how we are handling redirects on the initial render in this gist. Are you able to move your redirect to the server instead of doing it on the client?

A redirect on the client on the initial render is like a setState during render, which should be avoided if possible.

mjackson avatar Nov 09 '21 15:11 mjackson

Appreciate the quick reply @mjackson! This is for a (currently) basic client-side rendered app with no server side redirects. Note that the flicker happens every time the user navigates to / using the navigation links, not only the initial render.

mogelbrod avatar Nov 09 '21 15:11 mogelbrod

@mjackson I've been working on pure single page applications for many years now, and I think this use case is very common in such cases. If we're considering that routes can be registered in multiple places it's reasonable that a top route will redirect to somewhere like /profile while the profile page has multiple tabs, each with a unique sub-path for the NavLink effect, and we want to redirect to the first one in case we're at the index.

The flickering is a regression from what we have today. It'd be nice if this special case of redirecting directly from the routes definitions (without using element) would be officially addressed.

iMoses-Apiiro avatar Nov 10 '21 09:11 iMoses-Apiiro

In my case in my application's navigation menu I use a NavLink to a parent route so it will match child routes and I automatically redirect from the parent route to a child route. This trick is necessary because a NavLink can't match one route and link to another.

nathan-knight avatar Nov 12 '21 17:11 nathan-knight

Same here, not able to move redirect to server. It also doesn't make much sense for me as I would need to keep server and client routes in sync. I will probably switch back to the previous version though.

kresli avatar Nov 17 '21 11:11 kresli

@mjackson is there any possibility of react-router providing a way to redirect without the useEffect? Are there any additional things the community could help out with?

mogelbrod avatar Nov 22 '21 13:11 mogelbrod

This is still a big issue. The suggestion to move the logic to the server is largely irrelevant for people who maintain create-react-app web apps. React-router never said it was not compatible with client side routing as far as I know, so I feel disappointed that the maintainer have such low regard to people who do client side routing

slk333 avatar Aug 03 '22 20:08 slk333

I thought there was something wrong with my routing logic but apparently this is an issue with v6. I agree that this is a regression compared to v5. Is there a workaround to this or do I have to switch routers to fix this? Edit: I think I'll move back to v5 until this is fixed. Edit: v5 is working fine with react 18, no problems so far.

hichemfantar avatar Jan 02 '23 23:01 hichemfantar

Hey folks! Redirecting during render like this is essentially an issue because routing and rendering are tightly coupled. One of the primary drivers of the new Data APIs released in 6.4.0 is to decouple routing/data loading from rendering, so the way to get rid of this flicker is to redirect in a loader: https://codesandbox.io/s/react-router-v6-redirect-flash-forked-qzkw87.

brophdawg11 avatar Jan 09 '23 21:01 brophdawg11

Looks like the loader pattern fixes the issue. Thanks @brophdawg11 🎉

hichemfantar avatar Jan 09 '23 22:01 hichemfantar