I’m building a Next.js app (App router), and I’m using a custom useLoading hook to manage a loading state across the application with a context provider. Everything works perfectly in development mode (npm run dev), but when I build the app (npm run build) and run it in production, I get the following error:
Error: useLoading must be used within a LoadingProvider
It seems that the context is null after the build, even though it's wrapped properly with LoadingProvider in the root layout.
Here’s my code:
// src/context/LoadingContext.tsx
"use client";
import Loading from "@/pages/component/Loading";
import React, { createContext, FC, ReactNode, useState } from "react";
interface LoadingContextProps {
setLoading: React.Dispatch<React.SetStateAction<boolean>>;
}
interface LoadingProviderProps {
children: ReactNode;
}
const LoadingContext = createContext<LoadingContextProps | null>(null);
export const LoadingProvider: FC<LoadingProviderProps> = ({ children }) => {
const [isLoading, setLoading] = useState<boolean>(false);
return (
<LoadingContext.Provider value={{ setLoading }}>
<Loading isLoading={isLoading} />
{children}
</LoadingContext.Provider>
);
};
export default LoadingContext;
// src/hooks/useLoading.ts
import LoadingContext from "@/context/LoadingContext";
import { useContext } from "react";
export const useLoading = () => {
const context = useContext(LoadingContext);
if (!context) {
// context returns null here
throw new Error("useLoading must be used within a LoadingProvider", {
cause: context,
});
}
return context;
};
// src/app/layout.tsx
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en" suppressHydrationWarning>
<body>
<LoadingProvider>
<ThemeProvider defaultTheme="light">{children}</ThemeProvider>
</LoadingProvider>
</body>
</html>
);
}
usage:
const {setLoading} = useLoading();
setLoading(false);
setLoading(true);
Has anyone faced this issue before, or does anyone know what might be causing this behavior after the build?
Problems
In development mode (npm run dev), everything works fine. The useLoading hook returns the context as expected.
In building mode (npm run build), the context in useLoading becomes undefined, even though I’ve wrapped the component tree with LoadingProvider in the root layout.
I’m not sure why the context is working correctly in development but returns null on the process of building the app.
Things I've tried
- Double-checked that LoadingProvider is correctly wrapping the entire component tree.
- Verified that the issue only appears in the production build.
- Tried removing all implementation of the hooks (build successful).
useLoadinghook. works in dev mode but returns null in production.LoadingProvideris correctly imported in yourlayout.tsx. check components that rely on theLoadingProviderare marked as client-side components using "use client". these are some of the key points that come up when there are context handling.