Skip to content

Component doesn't unmount before router location/state changes while navigating, can cause infinite rendering聽#3340

Closed

Description

@xsjcTony

Which project does this relate to?

Router

Describe the bug

馃グIf you don't want to read all these detailed info with my real use cases, please refer to below comments for a real minimum reproduction, as it self-explained the issue.
馃グAlso please refer to this comment for what I've found and my thoughts about the issue.


I have a <ProtectedRoute /> component, which will redirect the application to / (landing page) if no such __INTERNAL_NAVIGATION__ flag is provided in the route state.

It's only wrapped in certain routes, and definitely the landing page is not wrapped with it.

However, once it detected the illegal visit to certain protected route, it should navigate back to / route immediately, but now it's somehow falling into infinity rerender until maximum update depth exceeded, behaves like the roote path / is wrapped by the <ProtectedRoute /> component as well, but it's definitely not.

Your Example Website or App

https://stackblitz.com/edit/github-bvu9xqjh?file=src%2Fcomponents%2FProtectedRoute.tsx

NOTE: Please take a look at the below comment if you want a straightforward & small reproduction which I find out later after posting this.

Steps to Reproduce the Bug or Issue

PATH A:

  1. Open console (I have pathname printed to the console for debugging)
  2. Click About link (It successfully redirect back to Home route, which is not wrapped by <ProtectedRoute /> but it's still rendering, causing infinite rerender)
  3. See the console

PATH B:
it's even worse. All navigation is valid, but it still breaks.

  1. Open console
  2. Click This-should-work link (This is a valid navigation because I passed the flag __INTERNAL_NAVIGATION__ to that protected route /this-should-work
  3. Click Home link (This is where things go wrong. Home route is not wrapped by <ProtectedRoute /> at all but it is still rendering it and cause infinite rerender)
  4. See the console

Expected behavior

It should redirect to / by only printing the error warning once (twice in StrictMode), with pathname /about.
But in reality, it falls into infinity rerendering, with pathname /about for once, but the rest are all /.
This shouldn't happen because / route is not wrapped by <ProtectedRoute /> component at all.

Screenshots or Videos

Image

Image

Platform

  • OS: Windows
  • Browser: Chrome
  • Version: 132.0.6834.160

Additional context

Currently migrating from react-router-dom to @tanstack/react-router. It worked fine in react-router-dom.

Activity

  1. xsjcTony commented on Feb 6, 2025

    @xsjcTony
    Author

    The ultimate conclusion is, after successfully navigating back to / (which is the Home page), <ProtectedRoute /> should be out of the component tree because it's not part of what's being defined in the component property of / route.

    But it's still rendering.

  2. changed the title [-]Wrong component rendered / Infinite rerender while navigating (馃檹Please see the content and help me with the title馃檹)[/-] [+]Wrong component rendered with the precense of `useLocation()`[/+] on Feb 6, 2025
  3. changed the title [-]Wrong component rendered with the precense of `useLocation()`[/-] [+]Wrong component rendered with the precense of `useLocation()`, can cause infinite rerender[/+] on Feb 6, 2025
  4. xsjcTony commented on Feb 6, 2025

    @xsjcTony
    Author

    This is the smallest reproduction I can make: https://stackblitz.com/edit/github-mqst1ckv?file=src%2Fcomponents%2FWeirdo.tsx

    Turns out the problem with the useLocation() called in the route's component property's component tree.

    Read the comment in the Weirdo.tsx and monitor the console while navigating back and forth, you'll know what's happening.

  5. changed the title [-]Wrong component rendered with the precense of `useLocation()`, can cause infinite rerender[/-] [+]Wrong component rendered with the presence of `useLocation()`, can cause infinite rerender[/+] on Feb 6, 2025
  6. xsjcTony commented on Feb 6, 2025

    @xsjcTony
    Author

    This is just so weird...

    I'm playing around the things in my real app, and found out that the route state is actually being modified first when a navigate() happens, then of course useLocation().state will be changed.
    But at that moment, the previous component is NOT unmounted yet.

    In my route /b, I'm checking whether something exists in the route state, if not I'm going to show an error screen.

    When I'm navigating to /a, route state has already been changed after calling navigate(), but the component of /b is NOT unmounted, so the error screen will show up until it actually unmounts.

    This is... from my perspective, it is FUNDAMENTALLY wrong.

    The ideal order should be

    1. navigate() called / <Link /> clicked, etc. whatever, navigation happened
    2. Unmount the previous route's component
    3. Update route state/location, etc.
    4. .... More router internal stuff that I don't know ....
    5. Mount the new route's component

    But currently, 2 is happening after 3, or even after 4.

    Sorry that I don't have much knowledge about how the router works exactly under the hood, but what I described above may also be the cause of all those issues.

    Please have a look and let me know, thanks.馃挌馃檹

  7. changed the title [-]Wrong component rendered with the presence of `useLocation()`, can cause infinite rerender[/-] [+]Wrong component rendered with the presence of `useLocation()`, can cause infinite rerender / Component didn't unmount before router location/state changes[/+] on Feb 6, 2025
  8. changed the title [-]Wrong component rendered with the presence of `useLocation()`, can cause infinite rerender / Component didn't unmount before router location/state changes[/-] [+]Wrong component rendered with the presence of `useLocation()`, can cause infinite rerender / Component doesn't unmount before router location/state changes[/+] on Feb 6, 2025
  9. changed the title [-]Wrong component rendered with the presence of `useLocation()`, can cause infinite rerender / Component doesn't unmount before router location/state changes[/-] [+]Component doesn't unmount before router location/state changes while navigating, can cause infinite rendering[/+] on Feb 6, 2025
  10. changed the title [-]Component doesn't unmount before router location/state changes while navigating, can cause infinite rendering[/-] [+]鈿狅笍鈥硷笍Component doesn't unmount before router location/state changes while navigating, can cause infinite rendering[/+] on Feb 7, 2025
  11. changed the title [-]鈿狅笍鈥硷笍Component doesn't unmount before router location/state changes while navigating, can cause infinite rendering[/-] [+]Component doesn't unmount before router location/state changes while navigating, can cause infinite rendering[/+] on Feb 8, 2025
  12. xsjcTony commented on Feb 8, 2025

    @xsjcTony
    Author

    Close in favour of #3110, hopefully someone can have a look and give an official comment on it whether this is the desired behaviour or what's recommended to do.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions