ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

GraphiQL 1.x 升级到 2.0.0 完全迁移指南:Props 变更、函数组件重构与主题系统

GraphiQL 1.x 升级到 2.0.0 完全迁移指南:Props 变更、函数组件重构与主题系统 GraphiQL 1.x 升级到 2.0.0 完全迁移指南Props 变更、函数组件重构与主题系统【免费下载链接】graphiqlGraphiQL the GraphQL LSP Reference Ecosystem for building browser IDE tools.项目地址: https://gitcode.com/GitHub_Trending/gr/graphiql本指南面向所有准备将graphiql从1.x升级到2.0.0的开发者。graphiql2带来了全新的 UI 设计含内置暗色主题、GraphiQL组件 Props 的破坏性变更、默认启用的多标签Tabs系统以及将底层架构从类组件重构为函数组件 React Context 的重大变化。读完本文你将掌握全部破坏性变更的对应方案能够把基于1.x编写的自定义实现无缝迁移到2.0.0并学会通过graphiql/react的 Context 与 Hook 体系读写 GraphiQL 内部状态。设计刷新全新的 UI 与内置暗色主题graphiql2最具视觉冲击力的变化是 UI 的全新设计。界面从零开始重做在保留简洁观感的同时更加现代并且首次内置了暗色主题。主题选择基于系统偏好prefers-color-scheme也可以通过设置对话框手动切换——点击屏幕左侧侧边栏底部的齿轮图标即可打开。从graphiql2开始官方支持的样式定制方式只有一种覆写通过 CSS 变量定义的设计令牌design tokens。相应地类名class name不再被视为稳定 API——如果你此前通过类名选择器覆写样式那么在未来的 minor 或 patch 版本中你的覆写可能失效这类变化不再属于破坏性变更。因此迁移时务必把基于类名的样式覆写全部改为基于 CSS 变量。所有可定制的 CSS 变量清单定义在graphiql/react包的 root.css 文件中。颜色类变量使用一组可直接传入 CSShsl()函数的值色相、饱和度、明度。以浅色主题为例.graphiql-container, .graphiql-dialog, .graphiql-dialog-overlay, .graphiql-tooltip, [data-radix-popper-content-wrapper] { /* Colors */ --color-primary: 320, 95%, 43%; --color-secondary: 242, 51%, 61%; --color-tertiary: 188, 100%, 36%; --color-info: 208, 100%, 46%; --color-success: 158, 60%, 42%; --color-warning: 36, 100%, 41%; --color-error: 13, 93%, 58%; --color-neutral: 219, 28%, 32%; --color-base: 219, 28%, 100%; }从源码可以看出主题系统不止覆盖这几个颜色令牌root.css还定义了透明度--alpha-secondary、--alpha-background-heavy等、字体--font-family、--font-family-mono、各级字号与字重、间距--px-2到--px-24、圆角--border-radius-*、弹层阴影与布局尺寸--sidebar-width: 60px、--toolbar-width: 40px、--session-header-height: 38.5px等一整套令牌。暗色模式通过media (prefers-color-scheme: dark)与body.graphiql-dark两类选择器覆写同一组令牌见 root.css例如--color-base从浅色的219, 28%, 100%变为暗色的219, 29%, 18%。主题的切换逻辑由graphiql/react的 Theme Slice 管理见 stores/theme.tssetTheme会把主题写入 storage、在document.body上添加或移除graphiql-light/graphiql-dark类并同步切换 Monaco 编辑器的主题未显式设置主题时通过window.matchMedia((prefers-color-scheme: dark))解析系统偏好。GraphiQL组件 Props 的破坏性变更graphiql2对GraphiQL组件的一组 Props 进行了破坏性调整迁移时需要逐一核对defaultVariableEditorOpen与defaultSecondaryEditorOpen合并为defaultEditorToolsVisibility。默认行为是当至少一个次级编辑器变量 / 请求头有内容时显示编辑器工具。可选值如下值行为false隐藏编辑器工具true显示编辑器工具variables显式显示变量编辑器headers显式显示请求头编辑器该 Props 的类型定义与默认逻辑可参见 GraphiQL.tsx 中GraphiQLInterfaceProps的 JSDoc以及GraphiQLInterface内部对initialVariables/initialHeaders的判定逻辑。docExplorerOpen、onToggleDocs与onToggleHistory被移除取而代之的是更通用的visiblePlugin用于控制哪个插件可见和onTogglePluginVisibility每当任意插件可见性变化时被调用。headerEditorEnabled更名为isHeadersEditorEnabled。在源码中它默认值为true用于控制请求头编辑器是否出现在编辑器工具中见 GraphiQL.tsx。ResultsTooltip更名为responseTooltip。Tabs 默认启用从graphiql1.8开始 Tabs 作为可选功能引入到graphiql2Tabs 始终开启。原先用于开关 Tabs 的tabsprop 被替换为onTabChange。如果你之前用tabsprop 传入回调函数可以这样迁移GraphiQL - tabs{{ onTabChange: (tabState) {/* do something */} }} onTabChange{(tabState) {/* do something */}} /交互行为当只打开一个会话时编辑器上方的标签栏是隐藏的右上角 Logo 旁的加号图标可以打开更多标签当至少打开两个标签时标签栏出现在编辑器上方。从源码看标签状态由EditorSlice全权管理见 stores/editor.tsaddTab、changeTab、moveTab、closeTab、updateActiveTabValues等 action 在更新标签时会同步各编辑器内容、调用onTabChange回调并通过防抖500ms将序列化后的标签状态持久化到 storagestoreTabs实现见 stores/editor.ts。切换或关闭标签时会先停止正在进行的请求actions.stop()关闭当前激活标签后会自动激活前一个标签若不存在则激活后一个。移除的包导出组件与工具函数的新家除GraphiQL组件本身外graphiql2移除了几乎所有 React 组件导出——它们都被迁移到了graphiql/react包中。下面是全部被移除导出及其新位置的对照被移除的导出graphiql现在的位置QueryEditor、VariableEditor、DocExplorergraphiql/react同名导出。注意DocExplorer的schemaprop 已不存在组件现在使用ExplorerContext提供的 schemaToolbarMenugraphiql/react的ToolbarMenuToolbarMenuItemgraphiql/react的ToolbarMenu.ItemToolbarSelectgraphiql/react的ToolbarListboxToolbarSelectOptiongraphiql/react的ToolbarListbox.OptiononHasCompletion不再导出仅供内部使用fillLeafs、getSelectedOperationName、mergeAstgraphiql/toolkit同名导出类型Fetcher、FetcherOpts、FetcherParams、FetcherResult、FetcherReturnType、Observable、Storage、SyncFetcherResultgraphiql/toolkit同名导出此前只是由graphiql重新导出这些迁移与仓库中的模块划分完全对应graphiql/react的入口 index.ts 统一导出useMonaco、utility、图标与全部components含ToolbarButton、ToolbarMenu、ToolbarListbox等见 components 目录graphiql/toolkit的入口 index.ts 则聚合导出async-helpers、create-fetcher、format、graphql-helpers与storage。其中fillLeafs实现位于 graphql-helpers/auto-complete.tsgetSelectedOperationName位于 graphql-helpers/operation-name.tsmergeAst位于 graphql-helpers/merge-ast.tsformatResult/formatError位于 format/index.ts。GraphiQL从类组件重构为函数组件graphiql1.x中的GraphiQL是类组件可以通过 ref 直接访问其 props、state 与方法。如下代码在2.0.0中不再工作因为 React 不允许给函数组件附加 refimport { createGraphiQLFetcher } from graphiql/toolkit; import { GraphiQL } from graphiql; import { Component } from react; const fetcher createGraphiQLFetcher({ url: https://my.endpoint }); class MyComponent extends Component { _graphiql: GraphiQL; componentDidMount() { const query this._graphiql.getQueryEditor().getValue(); } render() { return GraphiQL ref{r (this._graphiql r)} fetcher{fetcher} /; } }graphiql2将代码库重构为更现代的 React所有类组件被替换为函数组件。全部逻辑与状态管理现在分布在graphiql/react提供的多个 React Context 中。GraphiQL组件现在本质上只是组合了另外两个组件GraphiQLProvider来自graphiql/react渲染所有 Context Provider 并负责状态管理GraphiQLInterface定义在graphiql包内负责渲染 UI。如果你想在自定义实现中读写 GraphiQL 状态就必须分别渲染上述两个组件——因为消费 Context 值的 Hook 只能在 Provider 内部渲染的组件中工作。基于此上面的示例可以重构为import { useEditorContext } from graphiql/react; import { createGraphiQLFetcher } from graphiql/toolkit; import { GraphiQLInterface, GraphiQLProvider } from graphiql; import { useEffect } from react; const fetcher createGraphiQLFetcher({ url: https://my.endpoint }); function MyComponent() { return ( GraphiQLProvider fetcher{fetcher} InsideContext / /GraphiQLProvider ); } function InsideContext() { // 在 MyComponent 中调用这个 Hook 不会生效会返回 null const { queryEditor } useEditorContext(); useEffect(() { const query queryEditor.getValue(); }, [queryEditor]); return GraphiQLInterface /; }从当前仓库源码看GraphiQL_函数组件的实现GraphiQL.tsx正是将GraphiQLProvider与GraphiQLInterface组合它把defaultEditorToolsVisibility、isHeadersEditorEnabled、forcedTheme、confirmCloseTab等 Props 透传给 Interface同时把plugins默认[HISTORY_PLUGIN]与referencePlugin默认DOC_EXPLORER_PLUGIN注入 Provider。而GraphiQLProvider内部见 components/provider.tsx会用 zustand 创建包含 Editor、Execution、Plugin、Schema、Theme、Storage 六个 Slice 的 store并通过GraphiQLContext提供给子树useGraphiQL与useGraphiQLActions两个 Hookprovider.tsx是读写该 store 的标准入口。公开类方法及其替代方案下面是graphiql1中所有公开类方法在graphiql2中的替代方案涉及的 Context 均可通过graphiql/react导出的 Hook 访问1.x类方法2.0.0替代方案getQueryEditor使用EditorContext的queryEditor属性getVariableEditor使用EditorContext的variableEditor属性getHeaderEditor使用EditorContext的headerEditor属性refresh不再需要——所有编辑器在窗口调整大小后会自动刷新如确需手动刷新需对每个编辑器实例单独调用其refresh方法autoCompleteLeafs使用graphiql/react提供的useAutoCompleteLeafsHook返回该函数还有一批方法自graphiql1.9.0起就已移除但由于并未真正标记为private这里一并给出替代方案handleClickReference点击类型或字段时打开文档浏览器的回调。如需手动模拟可调用ExplorerContext的push方法向文档浏览器的导航栈压入条目并用PluginContext的setVisiblePlugin方法通过usePluginContext()获取传入graphiql/react提供的DOC_EXPLORER_PLUGIN对象以显示文档浏览器插件。handleRunQuery执行查询改用ExecutionContext的run方法如需显式设置操作名先调用EditorContext的setOperationName方法以操作名字符串为参数。handleEditorRunQuery使用ExecutionContext的run方法。handleStopQuery使用ExecutionContext的stop方法。handlePrettifyQuery使用graphiql/react的usePrettifyEditorsHook返回该函数。handleMergeQuery使用graphiql/react的useMergeQueryHook返回该函数。handleCopyQuery使用graphiql/react的useCopyQueryHook返回该函数。handleToggleDocs、handleToggleHistory使用PluginContext的setVisiblePlugin方法。以上用于修改状态的回调类方法handleEditQuery、handleEditVariables、handleEditHeaders、handleEditOperationName、handleSelectHistoryQuery、handleResetResize、handleHintInformationRender不打算被手动调用因此没有继任者。静态属性已移除graphiql1.x中GraphiQL类组件带有一批暴露工具函数与其他组件的静态属性绝大多数在2.0.0中被移除。仍然保留在GraphiQL函数组件上的只有GraphiQL.Logo、GraphiQL.Toolbar与GraphiQL.Footer它们都是可作为 children 传给GraphiQL组件的 React 组件用于覆写 UI 的特定部分GraphiQL.Logo覆写屏幕右上角的 logo。默认包含文字 GraphiQL。GraphiQL.Toolbar覆写操作编辑器旁边的工具栏。默认包含三个按钮美化当前编辑器内容prettify、把 fragment 定义合并进操作定义merge、复制操作编辑器内容到剪贴板copy。注意传入该组件作为 children 时默认按钮不会显示而是显示你传给GraphiQL.Toolbar的 children执行按钮ExecuteButton始终显示。如果想保留默认按钮并追加按钮应使用toolbarprop源码中执行按钮与自定义 toolbar 的渲染位置见 GraphiQL.tsx。GraphiQL.Footer在响应编辑器下方追加区块默认不显示。这些保留的静态属性在源码中通过Object.assign挂载见 GraphiQL.tsx。被移除的静态属性及其替代方案被移除的静态属性替代方案GraphiQL.formatResult、GraphiQL.formatErrorgraphiql/toolkit中同名函数GraphiQL.QueryEditor、GraphiQL.VariableEditor、GraphiQL.HeaderEditorgraphiql/react中同名组件GraphiQL.ResultViewergraphiql/react的ResponseEditor组件GraphiQL.Buttongraphiql/react的ToolbarButton组件GraphiQL.ToolbarButton与GraphiQL.Button相同同一组件GraphiQL.Menugraphiql/react的ToolbarMenu组件GraphiQL.MenuItemgraphiql/react的ToolbarMenu.Item组件GraphiQL.Group新版 UI 不再原生提供按钮并排分组能力在新版垂直工具栏中实现类似效果可自行给自定义工具栏元素添加样式例如import { createGraphiQLFetcher } from graphiql/toolkit; import { GraphiQL } from graphiql; const fetcher createGraphiQLFetcher({ url: https://my.endpoint }); function MyComponent() { return ( GraphiQL fetcher{fetcher} GraphiQL.Toolbar {/* 使用给定 class 为你的按钮添加自定义样式 */} div classNamebutton-group button1/button button2/button button3/button /div /GraphiQL.Toolbar /GraphiQL ); }window.g已移除在graphiql1.x中GraphiQL类组件会把自己的一份引用存储在名为g的全局属性上。由于函数组件不存在 ref这个属性已被移除而且它原本也只用于内部场景例如测试。迁移检查清单把上述变更汇总为一份可直接执行的升级清单样式搜索所有基于类名的 GraphiQL 样式覆写改为覆写 root.css 中的 CSS 变量同时确认暗色主题下的颜色令牌如--color-base、--color-neutral符合你的品牌要求。Props将defaultVariableEditorOpen/defaultSecondaryEditorOpen合并为defaultEditorToolsVisibility用visiblePlugin/onTogglePluginVisibility替换docExplorerOpen/onToggleDocs/onToggleHistory把headerEditorEnabled改为isHeadersEditorEnabled把ResultsTooltip改为responseTooltip。Tabs把tabs{{ onTabChange }}改为onTabChange并验证多标签行为符合预期。导入路径把QueryEditor、VariableEditor、ToolbarMenu等组件与fillLeafs、getSelectedOperationName、mergeAst等工具函数、以及Fetcher等类型改为从graphiql/react/graphiql/toolkit导入对照上文导出映射表。状态访问移除所有基于 ref 的_graphiql.getQueryEditor()之类调用改用GraphiQLProviderGraphiQLInterface组合并在 Provider 内部通过useEditorContext、useExecutionContext、usePluginContext等 Hook 读写状态refresh调用可整体删除。静态属性将GraphiQL.ResultViewer、GraphiQL.Button等替换为新包的组件GraphiQL.Logo、GraphiQL.Toolbar、GraphiQL.Footer可继续使用。全局变量删除任何依赖window.g的代码通常出现在测试代码中。如果在升级过程中遇到本指南未覆盖的问题欢迎在本仓库提交 issue 或 PR官方会持续补充这份迁移指南。【免费下载链接】graphiqlGraphiQL the GraphQL LSP Reference Ecosystem for building browser IDE tools.项目地址: https://gitcode.com/GitHub_Trending/gr/graphiql创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表