You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js应用中基于全局Context状态条件渲染Header的问题

Next.js Context状态异常问题解决

问题根源

你在_app.tsx里犯了一个关键错误:调用useContext(LoadingContext)的代码位于LoadingProvider组件的外层,这意味着你拿到的始终是创建Context时设置的默认值{ isLoading: true, ... },完全接收不到Provider内部状态更新后的新值。

而其他页面(比如index.tsx)能拿到正确的false,是因为这些页面组件被包裹在LoadingProvider内部,它们的useContext能正确订阅到Provider提供的动态状态。

修复方案

把需要使用Context状态的逻辑移到LoadingProvider内部即可,最简单的方式是抽离一个内部组件:

修改后的_app.tsx:

import { useContext } from 'react';
import { AppProps } from 'next/app';
import LoadingContext, { LoadingProvider } from '../path/to/your/context';
import { ThemeProvider } from 'your-theme-lib';
import theme from '../path/to/theme';
import Header from '../path/to/Header';
import Footer from '../path/to/Footer';

export default function App({ Component, pageProps }: AppProps) {
  return (
    <LoadingProvider>
      {/* 内部组件处于Provider覆盖范围内,可正常获取Context状态 */}
      <AppInner Component={Component} pageProps={pageProps} />
    </LoadingProvider>
  );
}

// 抽离内部组件,在Provider内部使用Context
function AppInner({ Component, pageProps }: { Component: React.ComponentType<any>, pageProps: any }) {
  const loadingCtx = useContext(LoadingContext);
  console.log(loadingCtx.isLoading); // 现在会输出正确的状态值

  return (
    <ThemeProvider theme={theme}>
      {!loadingCtx.isLoading && <Header />}
      <Component {...pageProps} />
      {!loadingCtx.isLoading && <Footer />}
    </ThemeProvider>
  );
}

额外优化建议

你当前在index.tsx里手动调用finishLoading的逻辑可以移到Context Provider内部,让状态管理更集中,避免在页面里分散逻辑:

修改后的Context代码:

import { useState, useEffect, createContext } from 'react';

type contextType = { isLoading: boolean; finishLoading: () => void };

const LoadingContext = React.createContext<contextType>({
  isLoading: true,
  finishLoading: () => {},
});

interface LoadingProviderProps {
  children: React.ReactNode;
}

export const LoadingProvider = ({ children }: LoadingProviderProps) => {
  const [loading, setLoading] = useState<boolean>(true);

  const finishLoading = () => {
    setTimeout(() => {
      setLoading(false);
    }, 4000);
  };

  // Provider挂载后自动触发加载结束逻辑
  useEffect(() => {
    finishLoading();
  }, []);

  return (
    <LoadingContext.Provider
      value={{ isLoading: loading, finishLoading: finishLoading }}
    >
      {children}
    </LoadingContext.Provider>
  );
};

export default LoadingContext;

这样你就可以删掉index.tsx里的useEffect逻辑,代码更简洁。

内容的提问来源于stack exchange,提问作者amir_70

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 23:30:45