import { useContext, useMemo } from "react"; import type { Client } from "urql"; /** * useGraphQLClient - 获取 urql client 单例 * * 用途:从 Shell 注入的 GraphQLProvider Context 中获取 urql client。 * 总裁裁决 §2.17 方案 A:Shell(teacher-portal)暴露 GraphQLProvider, * Remote(student/parent/admin)复用同一 client 单例,避免多实例 + 缓存不一致。 * * 注意:本 hook 必须在 GraphQLProvider 内部调用,否则抛出错误。 * * @example * const client = useGraphQLClient(); * const [result] = useQuery({ query: DashboardQuery }); * * MF 暴露:ARB-002 §2.2 exposes './useGraphQLClient' */ // GraphQLClientContext 由 Shell(apps/teacher-portal/src/app/providers.tsx)创建并注入。 // 此处通过 createContext 占位,Shell 在初始化时通过 Provider value 覆盖。 // 为避免 hooks 包直接依赖 urql(peerDependency),Context 值类型用 Client(urql 类型)。 // urql 在 apps/* 的 dependencies 中,通过 peerDependencies 声明。 import { createContext } from "react"; /** * GraphQL Client Context * * Shell(teacher-portal)通过 注入。 * Remote(student/parent/admin-portal)通过 MF shared 复用同一 Context 实例。 */ export const GraphQLClientContext = createContext(null); GraphQLClientContext.displayName = "GraphQLClientContext"; export interface UseGraphQLClientReturn { /** urql client 单例 */ client: Client; } export function useGraphQLClient(): UseGraphQLClientReturn { const client = useContext(GraphQLClientContext); if (!client) { throw new Error( "useGraphQLClient 必须在 GraphQLProvider 内部调用。" + "请确保组件树被 包裹(apps/teacher-portal/src/app/providers.tsx)。", ); } return useMemo(() => ({ client }), [client]); }