使用 @graphiql/react 构建 GraphQL 开发工具:Provider、状态 Store 与主题定制完全指南
【免费下载链接】graphiqlGraphiQL & the GraphQL LSP Reference Ecosystem for building browser & IDE tools.项目地址: https://gitcode.com/GitHub_Trending/gr/graphiql
导读
@graphiql/react是 GraphQL 生态官方维护的 React SDK,提供一套开箱即用的"积木",让开发者能够快速构建集成在 Web 应用中的 GraphQL IDE(如查询编辑器、变量编辑器、执行按钮等),它正是官方 GraphiQL IDE 自身的组件底座。本文将从最小示例出发,讲解如何用GraphiQLProvider组装状态、用useGraphiQL/useGraphiQLActions读写状态、理解六大 Store 切片职责,并介绍基于 CSS 变量的主题定制方式,最终让你掌握自建 GraphQL 开发体验的完整路径。
包概览与定位
@graphiql/react位于仓库 packages/graphiql-react,当前版本0.39.0。它是一个 React SDK,目标是"构建集成的 GraphQL Web 开发体验"。它的构建块分为两类:
- 有状态(Stateful)的 Context Provider:负责状态管理,例如 schema 的获取与校验、请求执行、主题、标签页、插件管理等;
- 无状态(Stateless)的 UI 组件:负责渲染,例如查询编辑器、工具栏按钮、对话框、下拉菜单等。
从 src/index.ts 的导出可以看到,它对外暴露了useMonaco、全部 utility、图标、组件、类型(如Theme、EditorProps、SchemaReference),以及KEY_MAP、formatShortcutForOS、isMacOs等常量工具。组件出口集中定义在 src/components/index.ts,其中QueryEditor是OperationEditor的别名、VariableEditor是VariablesEditor的别名、HeaderEditor是RequestHeadersEditor的别名。
依赖方面(见 package.json),它基于zustand管理状态、monaco-editor+monaco-graphql提供编辑器能力、@graphiql/toolkit提供 fetcher 与存储等底层设施,并使用 Radix UI 构建无障碍交互组件。peer 依赖要求graphql^15.5.0 || ^16.0.0 || ^17.0.0、react与react-dom^18 || ^19,意味着它同时兼容 React 18 与 19。
快速开始:最小的 GraphQL IDE
所有 IDE 状态都存在于多个 Context 中,最简单的入口是使用GraphiQLProvider,它会一次性渲染全部内部 Provider。它有一个必填 prop:fetcher——一个对指定端点执行 GraphQL 请求的函数。可以用@graphiql/toolkit的createGraphiQLFetcher快速创建:
import { GraphiQLProvider } from '@graphiql/react'; import { createGraphiQLFetcher } from '@graphiql/toolkit'; const fetcher = createGraphiQLFetcher({ url: 'https://my.graphql.api/graphql', }); function MyGraphQLIDE() { return ( <GraphiQLProvider fetcher={fetcher}> <div className="graphiql-container">Hello GraphQL</div> </GraphiQLProvider> ); }在 Provider 内部可以自由使用任意 UI 组件,例如渲染一个操作编辑器:
import { QueryEditor } from '@graphiql/react'; function MyGraphQLIDE() { return ( <GraphiQLProvider fetcher={fetcher}> <div className="graphiql-container"> <QueryEditor /> </div> </GraphiQLProvider> ); }引入必要的样式
包自带所有 UI 组件所需的 CSS,从@graphiql/react/style.css引入即可:
import '@graphiql/react/style.css';注意:要让这些样式生效,UI 组件必须渲染在带有
graphiql-containerclass 的元素内部。这是因为 src/style/root.css 将所有 CSS 变量(颜色、字体、间距、圆角等)定义在.graphiql-container及其关联类(.graphiql-dialog、.graphiql-tooltip等)的作用域内。
字体加载
默认情况下,UI 组件会尝试为正文使用 Roboto 字体、为等宽文本使用 Fira Code 字体。如果希望使用默认字体,可以加载以下两个文件:
@graphiql/react/font/roboto.css@graphiql/react/font/fira-code.css
也可以采用任何其他方式加载这两种字体(例如直接从字体 CDN 引入),包内对应文件位于 font 目录。
Provider 的运行时保护
在 src/components/provider.tsx 中,GraphiQLProvider在运行时对几个已移除的旧 API 做了显式抛错保护,了解这些能避免踩坑:
- 未传
fetcher会抛出TypeError:The GraphiQLProvider component requires a fetcher function to be passed as prop.; validationRulesprop 已移除,需改用自定义 GraphQL Worker(参见 monaco-graphql 包 中关于 custom webworker 的说明);query/variables/headers/response这些"受控 prop"已移除,统一改用initialQuery/initialVariables/initialHeaders初始化,之后通过useGraphiQL(state => state.queryEditor)拿到编辑器实例并调用setValue(...)编程式写入。
六大状态 Store:职责一览
GraphiQL 使用一组状态管理 Store,每个 Store 负责 IDE 行为的某一部分,全部逻辑可通过自定义 React Hooks 访问。useGraphiQL提供以下 Store 切片(各切片源码位于 src/stores):
| Store 切片 | 职责 | 源码 |
|---|---|---|
storage | 提供存储 API,用于在浏览器中持久化状态(默认使用localStorage) | src/stores/storage.ts |
editor | 管理query、variables、headers、response编辑器与标签页 | src/stores/editor.ts |
execution | 处理 GraphQL 请求的执行 | src/stores/execution.ts |
plugin | 管理插件与当前激活的插件 | src/stores/plugin.ts |
schema | 获取、校验并存储 GraphQL schema | src/stores/schema.ts |
theme | 管理当前主题并提供更新方法 | src/stores/theme.ts |
三个核心 Hooks
useMonaco:访问monaco-editor导出与monaco-graphql实例,专为 SSR 环境下的安全使用而设计。其底层实现在 src/stores/monaco.ts:monaco 与 monaco-graphql 是在useEffect中动态import的(而非静态 import),从而避免在 SSR(如 Next.js)服务端因window未定义而报错;同时会在初始化时注册graphiql-DARK/graphiql-LIGHT两套 Monaco 主题,并针对 Firefox 打上兼容补丁。useGraphiQL:访问当前状态。可传入 selector 选取状态子集(内部通过zustand的useShallow做浅比较,避免无谓重渲染)。useGraphiQLActions:触发会改变状态的 action。该 Hook永远不会触发重渲染——actions 是静态且不变化的函数集合,Provider 在创建 Store 时会把 editor/execution/plugin/schema/theme 五个切片的 actions 合并进统一的actions对象(见 provider.tsx)。
用法示例
import { useGraphiQL, useGraphiQLActions } from '@graphiql/react'; // 获取"获取 schema"与"切换主题"两个 action const { introspect, setTheme } = useGraphiQLActions(); // 用 selector 访问状态中的特定部分:当前 schema 与主题 const { schema, theme } = useGraphiQL(state => ({ schema: state.schema, theme: state.theme, }));所有 Store 属性都用 TSDoc 注释做了文档化,在 VSCode 等 IDE 中会自动弹出提示;这些描述也同步在包的 API Docs 中(provider.tsx 内useGraphiQL会在 Provider 树之外使用时抛出明确错误,帮助你及早发现问题)。
Store 细节与常用 Props
editor 切片(src/stores/editor.ts):除四个编辑器实例外,还持有tabs/activeTabIndex、initialQuery/initialVariables/initialHeaders、externalFragments、shouldPersistHeaders等状态。常用 props 与默认值:
| Prop | 默认值 | 说明 |
|---|---|---|
defaultQuery | "# Welcome to GraphiQL..." | 无存储内容且未传initialQuery时,首个标签页的初始查询(仅作用于第一个标签,后续标签页打开为空) |
shouldPersistHeaders | false | 是否将请求头编辑器的内容持久化到 storage |
defaultTabs | [] | 默认标签页集合(含 query/variables/headers),仅在 storage 中没有已持久化的标签状态时生效 |
externalFragments | — | 传入外部片段,可以是 SDL 字符串或FragmentDefinitionNode[],在 provider.tsx 的getExternalFragments中统一转换为Map<name, FragmentDefinitionNode> |
onEditOperationName/onTabChange/onCopyQuery/onPrettifyQuery | — | 各类编辑行为回调;onPrettifyQuery默认使用 prettier/standalone 的graphqlparser 格式化 |
execution 切片(src/stores/execution.ts):暴露run()与stop()两个 action。run()会依次完成:自动补全缺失的 leaf 字段(fillLeafs,并给插入的字段加 7 秒后自动清除的高亮装饰)、解析变量与请求头 JSON、附加 fragment 依赖、调用 fetcher,并兼容三种返回类型——Promise、Observable(订阅式流)与AsyncIterable(增量交付);同时实现了mergeIncrementalResult,用于将 @defer/@stream 等多段增量响应合并为完整结果。可通过operationNameprop 覆盖随请求发送的操作名。
schema 切片(src/stores/schema.ts):introspect()会根据需要发起 introspection 请求(可通过introspectionQueryName自定义查询名、inputValueDeprecation/schemaDescription控制查询选项),并用buildClientSchema构建 schema 后调用validateSchema校验。关键 props:
schema:显式传入GraphQLSchema、IntrospectionQuery结果,或传null明确禁止 introspection;不传则自动发起 introspection;dangerouslyAssumeSchemaIsValid(默认false):跳过 schema 校验。文档特别强调,不校验 schema 会让 GraphiQL 暴露于多种漏洞并可能崩溃,仅在你能完全掌控 schema 时才使用;onSchemaChange:每次构建出新的 schema 后回调(包括 introspection 与 prop 传入两种途径);customScalarSchemas:用 JSON Schema 描述自定义标量的合法取值,供变量编辑器做类型校验。例如{ GeoJSON: {}, DateTime: { type: 'string', format: 'date-time' } },避免自定义标量接受对象/数组时被误报 "Incorrect type"。
plugin 切片(src/stores/plugin.ts):pluginsprop 追加自定义插件(内置 doc explorer 与 history 之外),每个插件由title(唯一,重名会抛错)、icon、content三个字段构成;visiblePlugin可控制当前可见插件,referencePlugin用于定义点击类型时展示参考文档的插件。
theme 切片(src/stores/theme.ts):setTheme('light' | 'dark' | null)会写入 storage、在document.body上切换graphiql-light/graphiql-darkclass、并同步 Monaco 编辑器的主题。defaultThemeprop 默认null(跟随系统),editorThemeprop 可自定义暗/亮两套 Monaco 主题名(默认graphiql-DARK/graphiql-LIGHT)。
storage 切片(src/stores/storage.ts):storageprop 可传入自定义存储实现替换默认的localStorage(接口来自@graphiql/toolkit的StorageAPI)。
主题定制:CSS 变量体系
@graphiql/react的所有组件在设计之初就考虑了定制化,实现方式是CSS 变量。所有可定制变量都定义在 src/style/root.css 中,分为颜色、字体、间距、圆角、弹层样式、布局等几大类。
颜色:HSL 三元组
颜色使用HSL 格式定义,所有颜色 CSS 变量都是一个由三个值组成的列表(色相 hue、饱和度 saturation、明度 lightness),例如:
--color-primary: 320, 95%, 43%; --color-secondary: 242, 51%, 61%; --color-error: 13, 93%, 58%;这种设计让@graphiql/react可以把变量值传给hsla()函数来得到透明颜色:
background: hsla(var(--color-primary), var(--alpha-background-heavy));这样一来,无论元素背景是什么,都能保持良好对比度,实现真正可复用的 UI 元素。同时还有一组透明度变量(如--alpha-secondary: 0.76、--alpha-background-medium: 0.1)配合使用。暗色模式则通过@media (prefers-color-scheme: dark)媒体查询,在非强制亮色(body:not(.graphiql-light))时覆盖同一套变量。
覆盖变量的方式
在你的应用中,只需在graphiql-container作用域内覆盖对应变量即可定制主题,例如:
.graphiql-container { --color-primary: 210, 90%, 50%; --font-size-body: calc(16rem / 16); }本地开发与联调
在本地开发@graphiql/react(尤其是配合graphiql主包一起开发)时,只需在包目录内运行:
yarn dev它会用 Vite 以监听模式构建该包(脚本定义见 package.json)。再结合仓库根目录运行的yarn dev:graphiql,就能在同时修改graphiql与@graphiql/react时获得热重载体验。相关测试可在包内运行yarn test(vitest)。
参考实现
如需查看@graphiql/react的完整用法,官方参考实现就是 GraphiQL 本身,其组件组装位于 packages/graphiql/src/GraphiQL.tsx——它把GraphiQLProvider、各个编辑器、工具栏、插件(如 doc explorer、history)组合成了完整 IDE。仓库中还有大量围绕该 SDK 的实战示例,例如 examples/graphiql-vite、examples/graphiql-nextjs、examples/graphiql-webpack 等,可作为接入不同构建工具的参考。
小结
通过本文你可以掌握@graphiql/react的三层用法:一是用GraphiQLProvider+createGraphiQLFetcher搭建最小可用的 IDE 骨架并引入样式与字体;二是借助useGraphiQL(读)与useGraphiQLActions(写,永不重渲染)自由读写六大 Store 切片,理解 editor/execution/schema/plugin/theme/storage 各自的职责边界;三是基于 HSL 三元组的 CSS 变量体系实现轻量主题定制。这套 SDK 既可以支撑完整的 GraphiQL 体验,也可以被拆散为任意组合的积木,嵌入你自己的产品中。
【免费下载链接】graphiqlGraphiQL & the GraphQL LSP Reference Ecosystem for building browser & IDE tools.项目地址: https://gitcode.com/GitHub_Trending/gr/graphiql
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考