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

如何在React-Router-6的loader中访问全局Context的setIsLoading?

解决方案:React Router 6 Loader 中修改全局加载状态

由于 React Router 的 loader 函数运行在组件渲染上下文之外,无法直接调用 React Hooks(包括 useContext),因此可以通过以下两种方案解决:

方案一:利用 React Router 内置导航状态(推荐)

React Router 6 提供的 useNavigation 钩子可以直接获取路由加载状态,无需自行维护全局 Context:

  1. 创建全局加载组件
// components/GlobalLoading.jsx
import { useNavigation } from "react-router-dom";

export default function GlobalLoading() {
  const navigation = useNavigation();
  const isLoading = navigation.state === "loading";

  return isLoading ? (
    <div style={{ position: "fixed", top: 0, left: 0, right: 0, bottom: 0, background: "rgba(0,0,0,0.5)", display: "flex", alignItems: "center", justifyContent: "center", color: "white" }}>
      加载中...
    </div>
  ) : null;
}
  1. 在布局组件中引入
// 修改 AppLayout
const AppLayout = () => (
  <>
    <GlobalLoading />
    <MenuBar />
    <Outlet />
  </>
);

这个方案无需修改现有 loader 和 Context,直接复用 React Router 内置的加载状态,覆盖所有路由 loader 的加载场景。

方案二:独立状态管理模块(自定义加载逻辑)

如果需要自定义加载逻辑(比如同时管理 loader 之外的异步请求),可以创建独立的状态管理模块,脱离 React Context 限制:

  1. 创建加载状态管理文件
// utils/loadingState.js
let isLoading = false;
const listeners = [];

export const setLoading = (newState) => {
  isLoading = newState;
  listeners.forEach(listener => listener(isLoading));
};

export const getLoading = () => isLoading;

export const subscribeLoading = (listener) => {
  listeners.push(listener);
  // 返回取消订阅函数
  return () => {
    listeners = listeners.filter(l => l !== listener);
  };
};
  1. 集成到 GlobalContext
// 修改 GlobalContext.jsx
import {
  createContext,
  useContext,
  useEffect,
  useState,
  ReactNode,
} from "react";
import { getLoading, setLoading, subscribeLoading } from "../utils/loadingState";

interface GlobalContextValue {
  isLoading: boolean;
  setIsLoading: (newState: boolean) => void;
}

const GlobalContext = createContext<GlobalContextValue>({
  isLoading: false,
  setIsLoading: () => {},
});

export const useGlobalContext = () => useContext(GlobalContext);

export const GlobalProvider: React.FC<{ children: ReactNode }> = ({ children }) => {
  const [localIsLoading, setLocalIsLoading] = useState(getLoading());

  useEffect(() => {
    // 订阅状态变化,同步到组件状态
    const unsubscribe = subscribeLoading(newState => {
      setLocalIsLoading(newState);
    });
    return unsubscribe;
  }, []);

  const handleSetIsLoading = (newState) => {
    setLoading(newState);
  };

  return (
    <GlobalContext.Provider
      value={{
        isLoading: localIsLoading,
        setIsLoading: handleSetIsLoading,
      }}
    >
      {children}
    </GlobalContext.Provider>
  );
};
  1. 在 loader 中调用状态修改
// 修改 profileLoader
import { setLoading } from "../utils/loadingState";

const profileLoader = async () => {
  setLoading(true);
  try {
    const auth = getAuth();
    const user = auth.currentUser;
    const result = await getUserById(user?.email);
    return result || null;
  } finally {
    // 无论请求成功失败都关闭加载状态
    setLoading(false);
  }
};

这个方案允许 loader 和组件共享同一加载状态,同时支持自定义扩展。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 03:50:31