TanStack / router

🤖 Fully typesafe Router for React (and friends) w/ built-in caching, 1st class search-param APIs, client-side cache integration and isomorphic rendering.
https://tanstack.com/router
MIT License
8.16k stars 637 forks source link

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

Open SalzstangeSalamiBrief opened 2 months ago

SalzstangeSalamiBrief commented 2 months ago

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

Additional context

No response

luansevero commented 2 months ago

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>,
});
SalzstangeSalamiBrief commented 2 months ago

Thanks for you answer. After setting the suggested flag the pendingComponentis 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?