Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

useRouteLoaderData in the main Layout component (root.tsx) results in Invalid hook call, TypeError: Cannot read properties of null (reading 'useContext') #12786

Open
tomerzcod7 opened this issue Jan 20, 2025 · 8 comments
Labels

Comments

@tomerzcod7
Copy link

I'm using React Router as a...

framework

Reproduction

Every once in a while, when I start my RR7 app, I get an error from the main Layout component in the root.tsx file. It doesn't happen every time and usually resolves after I refresh the page.
This my very basic root.tsx file, with just added support color scheme type hint:

import {
  isRouteErrorResponse,
  Links,
  Meta,
  Outlet,
  Scripts,
  ScrollRestoration,
  useRouteLoaderData,
} from 'react-router';

import type { Route } from './+types/root';
import stylesheet from './app.css?url';

export const links: Route.LinksFunction = () => [
  { rel: 'preconnect', href: 'https://fonts.googleapis.com' },
  {
    rel: 'preconnect',
    href: 'https://fonts.gstatic.com',
    crossOrigin: 'anonymous',
  },
  {
    rel: 'stylesheet',
    href: 'https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,100..700;1,100..700&display=swap',
  },
  { rel: 'stylesheet', href: stylesheet },
];

// Todo: add support for theme toggling with cookie
export async function loader({ request }: Route.LoaderArgs) {
  const prefersDark =
    request.headers.get('Sec-CH-Prefers-Color-Scheme') === 'dark';
  return { prefersDark };
}

export function Layout({ children }: { children: React.ReactNode }) {
  const data = useRouteLoaderData<Awaited<ReturnType<typeof loader>>>('root');

  return (
    <html lang="en" className={data?.prefersDark ? 'dark' : ''}>
      <head>
        <meta charSet="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <Meta />
        <Links />
      </head>
      <body>
        {children}
        <ScrollRestoration />
        <Scripts />
      </body>
    </html>
  );
}

export default function App() {
  return <Outlet />;
}

export function ErrorBoundary({ error }: Route.ErrorBoundaryProps) {
  let message = 'Oops!';
  let details = 'An unexpected error occurred.';
  let stack: string | undefined;

  if (isRouteErrorResponse(error)) {
    message = error.status === 404 ? '404' : 'Error';
    details =
      error.status === 404 ?
        'The requested page could not be found.'
      : error.statusText || details;
  } else if (import.meta.env.DEV && error && error instanceof Error) {
    details = error.message;
    stack = error.stack;
  }

  return (
    <main className="container mx-auto p-4 pt-16">
      <h1>{message}</h1>
      <p>{details}</p>
      {stack && (
        <pre className="w-full overflow-x-auto p-4">
          <code>{stack}</code>
        </pre>
      )}
    </main>
  );
}

It seems like the error originates from calling the useRouteLoaderData in the Layout component.
I've implemented this code according to https://reactrouter.com/explanation/special-files#layout-export docs

I appreciate any help and would be happy to share more information.

System Info

System:
    OS: macOS 15.2
    CPU: (11) arm64 Apple M3 Pro
    Memory: 177.55 MB / 36.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 23.3.0 - ~/.nvm/versions/node/v23.3.0/bin/node
    npm: 10.9.0 - ~/.nvm/versions/node/v23.3.0/bin/npm
    pnpm: 9.15.3 - /opt/homebrew/bin/pnpm
    bun: 1.1.38 - ~/.bun/bin/bun
    Watchman: 2024.12.02.00 - /opt/homebrew/bin/watchman
  Browsers:
    Chrome: 131.0.6778.265
    Safari: 18.2
  npmPackages:
    vite: ^6.0.7 => 6.0.7

Used Package Manager

pnpm

Expected Behavior

The app should render properly without invalid hooks and and react context errors

Actual Behavior

I get the following errors in the browser:

Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://react.dev/link/invalid-hook-call for tips about how to debug and fix this problem. Error Component Stack
    at Layout (root.tsx:49:3)
    at RenderErrorBoundary (chunk-2MFAD2GV.js?v=807df968:5160:5)
    at DataRoutes (chunk-2MFAD2GV.js?v=807df968:5789:3)
    at Router (chunk-2MFAD2GV.js?v=807df968:5874:13)
    at RouterProvider (chunk-2MFAD2GV.js?v=807df968:5619:3)
    at RouterProvider2 (<anonymous>)
    at RemixErrorBoundary (chunk-2MFAD2GV.js?v=807df968:6789:5)
    at HydratedRouter (react-router_dom.js?v=18831c49:146:46)
TypeError: Cannot read properties of null (reading 'useContext')
    at exports.useContext (http://localhost:5173/node_modules/.vite/deps/chunk-3ISELJEO.js?v=6110a1c3:1082:27)
    at useDataRouterState (http://localhost:5173/node_modules/.vite/deps/chunk-QGJ7HSHL.js?v=6110a1c3:5487:22)
    at useRouteLoaderData (http://localhost:5173/node_modules/.vite/deps/chunk-QGJ7HSHL.js?v=6110a1c3:5559:15)
    at Layout (http://localhost:5173/app/root.tsx:52:16)
    at react-stack-bottom-frame (http://localhost:5173/node_modules/.vite/deps/react-dom_client.js?v=18831c49:16192:20)
    at renderWithHooks (http://localhost:5173/node_modules/.vite/deps/react-dom_client.js?v=18831c49:4306:24)
    at updateFunctionComponent (http://localhost:5173/node_modules/.vite/deps/react-dom_client.js?v=18831c49:5972:21)
    at beginWork (http://localhost:5173/node_modules/.vite/deps/react-dom_client.js?v=18831c49:7048:20)
    at runWithFiberInDEV (http://localhost:5173/node_modules/.vite/deps/react-dom_client.js?v=18831c49:726:18)
    at performUnitOfWork (http://localhost:5173/node_modules/.vite/deps/react-dom_client.js?v=18831c49:10831:98)
@tomerzcod7 tomerzcod7 added the bug label Jan 20, 2025
@yoni-noma
Copy link

yoni-noma commented Jan 26, 2025

im having the same issue in a different context, if my app is idle for some time, and i navigate im also getting
TypeError: Cannot read properties of null (reading 'useContext'). not sure whats is the source

I think that it related to the useRouteLoaderData loosing context for some reason
maybe related to server caching build?

@Alex793x
Copy link

I'll be following along here, since we are experiencing the same issue

@DennisKraaijeveld
Copy link

This only happens locally and on first page/route load here.

@itsjavi
Copy link

itsjavi commented Feb 1, 2025

@DennisKraaijeveld same to me, since I wrapped my layout in a NuqsAdapter import { NuqsAdapter } from 'nuqs/adapters/react-router/v7'. I think it's because of the same reason as mentioned.

@R-Bower
Copy link

R-Bower commented Feb 2, 2025

This also appears to happen with useLoaderData

@thomaswelton
Copy link

im having the same issue in a different context, if my app is idle for some time, and i navigate im also getting TypeError: Cannot read properties of null (reading 'useContext'). not sure whats is the source

I think that it related to the useRouteLoaderData loosing context for some reason maybe related to server caching build?

I've left a comment on the remix repo about a similar issue. Could this also describe your issue?
remix-run/remix#10455 (comment)

@yoni-noma
Copy link

For anyone who encounters this in their development, please read this discord message by the @tomerzcod7

It solved my issue on dev.
*regarding production, you should look at this issue.

@tomerzcod7
Copy link
Author

tomerzcod7 commented Feb 4, 2025

Hey guys, I found a solution that fixed this for me (for the most part), this is a copy paste from the Remix discord

For anyone fighting with the "Cannot read properties of null (reading 'useContext')" error on dev server startup, when installing new dependencies or deleting node_modules etc, I've gone deep down the rabbit hole with this one and I found 2 solutions that fix this issue for me.

Seems like this is caused by the way Vite dev server does dependency optimization, which happens when there's no vite cache (node_modules/.vite) folder, or when the cache is expired, when you install new dependency, package-lock changes, etc.

I'm still not sure exactly which dependencies cause this and why but some dependencies when they are being optimized on initial page load cause the client app to crash.

One fix that worked for me was using the Vite server warmup option (https://vite.dev/config/server-options.html#server-warmup) like this:

server: {
    warmup: {
      clientFiles: [
        './app/components/**/*',
        './app/entry.client.tsx',
        './app/root.tsx',
        './app/routes/**/*',
        '!**/*.server.ts',
      ],
    },
  },

I basically needed to keep adding files here until at some point the app stopped crashing (even though it still optimizes some dependencies, apparently specific dependencies are causing the issue).

Another solution I found which is a bit easier is using a future remix flag - https://remix.run/docs/en/main/guides/dependency-optimization

 future: {
    unstable_optimizeDeps: true,
  },

After setting this up, Vite doesn't need to optimize any dependencies on initial page load except of the react-router-devtools/client package, which still causes my app to crash.

To fix the issue with that one I had 2 choices either remove the devtools completely from vite.config file or do this:

 server: {
    warmup: {
      clientFiles: ['./app/root.tsx'],
    },
  },

If anyone knows about any downsides to these fixes (especially about the unstable_optimizeDeps flag) would love to get some more info 🙂

Hope this helps!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

7 participants