#Accessing useLoaderData in nested component.

1 messages · Page 1 of 1 (latest)

vivid mural
#

Hello. I am using React Router 7. In my root loader, I am checking for a session like so:

export async function loader({ request }: Route.LoaderArgs) {
  const data = await checkSessionApi(request);

  return data;
}

In my app layout file, I want to access this information so I can properly render the appropriate links in my header:

import { Link, Outlet, useLoaderData, useMatches } from 'react-router';
import type { loader } from './root';

export default function AppLayout() {
  return (
    <div className='grid m-auto'>
      <Header />
      <Outlet />
    </div>
  );
}

function Header() {
  // Why does this useLoaderData call not work?
  const data = useLoaderData<typeof loader>();
  console.log(data);
  return (
    <div className='p-4 flex justify-between items-center'>
      <div>
        <Link to={'/'} className='font-bold text-xl'>
          YATA
        </Link>
        <div className='text-sm '>(Yet Another Todo App)</div>
      </div>
      <nav>
        <ul className='flex gap-5'>
          {!data ? (
            <>
              <li>
                <Link to={'login'}>Login</Link>
              </li>
              <li>
                <Link to={'register'}>Register</Link>
              </li>
            </>
          ) : (
            <li>Logout</li>
          )}
        </ul>
      </nav>
    </div>
  );
}

The issue I am running into is that this data is returning null, where in my root.tsx file, it is defined. Could anyone point me in the right direction? Thanks 🙂

tribal kettle
#

useLoaderData() returns the loader data for the currently rendering route. Since you're importing the root loader type, I'm assuming you want to access the loader data for the root route, rather than your layout route. In that case, what you want is useRouteLoaderData(), which expects a route id (in this case, "root").

- const data = useLoaderData<typeof loader>();
+ const data = useRouteLoaderData<typeof loader>("root");

Since React Router can't guarantee that the route id you use will actually be in the current set of matched routes, the type signature for useRouteLoaderData() includes | undefined, so you'll need to ensure you properly handle that case. In this instance, since root is rendered for everything, you can probably get away with using the non-null assertion operator:

const data = useRouteLoaderData<typeof loader>("root")!; // <- notice the ! at the end