Skip to content

createRootRoute does not render the pending component on initial page visit #2182

Closed

Description

@SalzstangeSalamiBrief

Describe the bug

Hello,

I want to load data that is relevant for the whole page (e.g. user related data) on the first load of the page and use it through the whole application where it is needed.
For that scenario, a loader function is added to the root of the application (__root.tsx).
Now the data is properly loaded and can be used through the whole application by using the function useLoaderData of the exported root component.
The problem is that while the loader is not resolved, an empty page is displayed.
Instead of an empty page, a loading spinner (or something else) should be displayed.
To achieve this behavior, a pendingComponent is added to the root.
The problem is that the component added as pendingComponent is not rendered so that the page is still empty while loading the page/data.

Your Example Website or App

https://stackblitz.com/edit/tanstack-router-4vc1d6?file=src%2Froutes%2F__root.tsx,src%2Fmain.tsx,src%2Froutes%2Findex.tsx&preset=node

Steps to Reproduce the Bug or Issue

Visit/reload the page

Expected behavior

Expected:
As a user, I expect that a pending component is shown while the loader is not resolved to ease the perceived loading time.

Current:
As a user I see an empty page without content so that I perceive the page as broken.

Screenshots or Videos

No response

Platform

  • OS: Windows
  • Browser: Chrome, Firefox, Firefox Developer Edition, Edge

Additional context

No response

Activity

  1. luansevero commented on Sep 7, 2024

    @luansevero

    Need to set the wrapInSuspense option to true

    import { Outlet, createRootRoute } from '@tanstack/react-router';
    
    export const Route = createRootRoute({
      component: () => (
        <>
          <h1>Hello Root</h1>
          <Outlet />
        </>
      ),
      loader: () => new Promise((resolve) => setTimeout(resolve, 2000)),
      wrapISuspense: true,
      pendingComponent: () => <h2>pending</h2>,
    });
    
  2. SalzstangeSalamiBrief commented on Sep 9, 2024

    @SalzstangeSalamiBrief
    Author

    Thanks for you answer.
    After setting the suggested flag the pendingComponent is properly displayed.
    But now I am a bit confused:
    As a substitute i used the defaultPendingComponent while initializing the router via createRouter:

    import React from 'react';
    import ReactDOM from 'react-dom/client';
    import { RouterProvider, createRouter } from '@tanstack/react-router';
    import { routeTree } from './routeTree.gen';
    
    // Set up a Router instance
    const router = createRouter({
      routeTree,
      defaultPendingComponent: () => <h2>Main Pending</h2>
    });
    
    // Register things for typesafety
    declare module '@tanstack/react-router' {
      interface Register {
        router: typeof router;
      }
    }
    
    const rootElement = document.getElementById('app')!;
    
    if (!rootElement.innerHTML) {
      const root = ReactDOM.createRoot(rootElement);
      root.render(<RouterProvider router={router} />);
    }

    This renders the pending component while the loader in __root.tsx is not resolved without using wrapInSuspense flag.
    Do you know why that is?

  3. TkDodo commented on Nov 23, 2024

    @TkDodo
    Contributor

    This code here shows that having wrapInSuspense: true is necessary for root routes:

    const ResolvedSuspenseBoundary =
    // If we're on the root route, allow forcefully wrapping in suspense
    (!route.isRoot || route.options.wrapInSuspense) &&

    So maybe it just needs documenting?

    I’m not entirely sure why adding a defaultPendingComponent changes this. @schiller-manuel ?

  4. jakec-dev commented on Mar 11, 2025

    @jakec-dev

    This doesn't seem to work in Tanstack Start. I don't see the pending component as the loader is running. The favicon spins showing the route is loading, then it just loads the component.

    Note this includes fixing the typo wrapISuspense

    Need to set the wrapInSuspense option to true

    import { Outlet, createRootRoute } from '@tanstack/react-router';
    
    export const Route = createRootRoute({
      component: () => (
        <>
          <h1>Hello Root</h1>
          <Outlet />
        </>
      ),
      loader: () => new Promise((resolve) => setTimeout(resolve, 2000)),
      wrapInSuspense: true,
      pendingComponent: () => <h2>pending</h2>,
    });
    
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

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions