Next.js构建后React Context返回null,开发模式正常
问题描述
我正在使用Next.js App Router开发应用,通过自定义useLoading钩子结合Context Provider管理全局加载状态。开发模式(npm run dev)下一切正常,但执行npm run build构建生产版本后,出现错误:Error: useLoading must be used within a LoadingProvider,此时useLoading中的Context返回null,尽管已在根布局中正确包裹LoadingProvider。
相关代码
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> ); }
使用方式
const {setLoading} = useLoading(); setLoading(false); setLoading(true);
已尝试的操作
- 确认
LoadingProvider已正确包裹整个组件树 - 验证问题仅出现在生产构建版本
- 移除钩子相关实现后构建成功
解决方案
这个问题的核心原因是Next.js App Router的生产构建会对服务端组件(Server Component)做严格的静态分析:如果某个组件在服务端渲染阶段调用了useLoading钩子,而LoadingProvider是客户端组件(带有"use client"指令),服务端渲染时无法获取客户端Context,就会抛出这个错误。开发模式未做严格校验,所以不会触发问题。
具体修复步骤:
- 给所有调用
useLoading的组件添加"use client"指令:Context和自定义钩子只能在客户端组件中使用,在这些组件的最顶部加上"use client",明确标记为客户端组件。 - 检查组件边界:确认
ThemeProvider如果是客户端组件,也已正确添加"use client"指令,避免嵌套的客户端组件边界问题。 - 禁止在服务端组件中调用客户端钩子:生产构建的静态分析会严格拦截服务端组件中的客户端API调用,必须确保
useLoading只在客户端组件内使用。 - 临时排查方案(不推荐用作最终修复):可以给Context设置一个空默认值,避免直接抛出错误,方便排查问题组件:
const LoadingContext = createContext<LoadingContextProps>({ setLoading: () => {} });
关键提醒
Next.js App Router中服务端组件与客户端组件的边界必须清晰:
- 客户端组件(带
"use client")可使用React状态、Context、自定义钩子等客户端API - 服务端组件禁止使用任何客户端专属API,生产构建会做严格校验
内容的提问来源于stack exchange,提问作者Agu
相关产品推荐
相关产品推荐

