ARTICLE DETAIL

资讯详情

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

在 React Static 中集成 Apollo:构建时静态数据与客户端实时查询的完整指南

在 React Static 中集成 Apollo:构建时静态数据与客户端实时查询的完整指南 前端开发工具【免费下载链接】react-static⚛️ A progressive static site generator for React.项目地址https://gitcode.com/gh_mirrors/re/react-static点击查看免费下载本文基于 docs/guides/apollo.md 编写讲解如何在 React Static 静态站点生成器中集成 Apollo Client。文章覆盖三种典型场景客户端实时数据获取、构建期静态数据获取以及二者混合使用例如电商场景中商品静态信息 实时库存/价格并结合仓库源码揭示static.config.js、getRoutes与useRouteData的底层执行机制帮助读者写出可运行的完整集成方案。为什么要在 React Static 中使用 ApolloReact Static 是一款渐进式的 React 静态站点生成器见 README.md它把「构建时生成静态 HTML」与「运行时水合hydration为完整的 React 应用」结合起来。在这一架构下GraphQL 数据获取通常有两个不同的时机对应的正是 Apollo 的两种典型用法构建时build time在生成静态路由和页面时查询 GraphQL API将结果写入静态 HTML用于 SEO 优化与首屏性能。适合变化缓慢的数据例如电商场景中的商品名称、描述、图片。客户端client side在浏览器中向 GraphQL API Server 发起实时查询或通过 GraphQL Mutation 更新数据。适合快速变化的数据例如库存数量、实时价格以及用户下单等交互操作。这两个场景可以独立使用也可以同时使用——这正是本文要完整演示的内容。客户端数据获取像普通 React 项目一样使用 Apollo在 React Static 中做客户端数据获取与在普通 React 项目或 create-react-app 中几乎完全一致只有一个关键区别必须使用完整的apollo-client包而不是apollo-boost因为你需要自定义 Apollo Client具体来说必须为HttpLink显式指定node-fetch作为 fetch 方法因为同样的查询也会在 Node 环境中被调用。为什么需要node-fetch原因是构建期执行static.config.js时代码运行在 Node.js 进程里见下文「构建时数据获取」Apollo 的HttpLink在发起 HTTP 请求时需要全局fetch而 Node 默认环境并不提供浏览器端的fetch实现。统一指定node-fetch可以保证同一份 client 模块在浏览器水合与 Node 构建两种环境下都能正常工作。安装依赖首先安装所需的全部包yarn add apollo-client apollo-cache-inmemory apollo-link-http react-apollo graphql-tag graphql node-fetch各包职责如下包作用apollo-clientApollo Client 核心管理查询缓存、请求队列与数据状态apollo-cache-inmemory默认的内存缓存实现InMemoryCacheapollo-link-http提供HttpLink负责将查询请求发送到 GraphQL 端点react-apolloReact 绑定提供ApolloProvider、Query、Mutation等组件graphql-tag提供gql模板标签用于书写查询语句graphqlGraphQL 解析器基础库node-fetchNode 环境的 fetch 实现用于构建期的 HTTP 请求创建 Apollo Client 模块新建一个模块导出你的 Apollo Client例如项目中的src/apolloClient.jsimport { ApolloClient } from apollo-client import { HttpLink } from apollo-link-http import { InMemoryCache } from apollo-cache-inmemory import fetch from node-fetch const client new ApolloClient({ link: new HttpLink({ uri: https://your-api-server/graphql, fetch, }), cache: new InMemoryCache(), }) export default client其中uri指向你的 GraphQL API 地址fetch显式传入node-fetch。这一模块会被浏览器端和构建端static.config.js共同引用因此是双端复用的关键。用 ApolloProvider 包裹应用在应用入口通常是src/App.js中用ApolloProvider包裹需要查询 GraphQL 的组件。以 React Static 默认模板结构为例对应 packages/react-static/templates/basic/src/App.js 的模式import React from react import { Root, Routes } from react-static import { Link } from reach/router import { ApolloProvider } from react-apollo import client from ./apolloClient import ./app.css function App() { return ( ApolloProvider client{client} Root nav Link to/Home/Link Link to/productsProducts/Link /nav div classNamecontent Routes / /div /Root /ApolloProvider ) } export default AppApolloProvider通过 React Context 将client下发给所有后代组件之后任意页面组件都可以使用react-apollo的Query/Mutation组件或 Hooks 进行实时数据操作。至此客户端数据获取的配置即告完成。构建时数据获取在 static.config.js 中复用同一个 Client构建时数据获取的实现思路非常简洁直接复用上一步创建的同一个 Apollo Client在static.config.js中查询数据并生成路由。示例生成商品列表与商品详情路由下面的示例在构建期查询商品列表生成/products路由并注入products数据属性同时为每个商品生成子路由/products/:seoName注入对应的product数据import client from ./src/apolloClient import GET_PRODUCTS from ./src/graphql/getProducts export default { getSiteData: () ({ title: React Static, }), getRoutes: async () { const { data: { allProducts: products }, } await client.query({ query: GET_PRODUCTS, }) return [ { path: /products, template: src/pages/Products, getData: () ({ products, }), children: products.map(product ({ path: /${product.seoName}, template: src/pages/Product, getData: () ({ product, }), })), }, ] }, }其中getSiteData返回全站共享数据示例中是站点标题getRoutes返回路由树父路由/products通过template指向页面组件getData提供页面渲染所需的数据children用于声明动态子路由路径使用模板字符串拼接出/:seoName形式的动态段。底层原理getRoutes 与 getData 是如何被调用的getRoutes是 React Static 构建流程的核心钩子。在 packages/react-static/src/static/getRoutes.js 中可以看到构建期会依次收集插件路由与用户路由const pluginRoutes await plugins.getRoutes([], state) const userRoutes await state.config.getRoutes(state) const routes [...pluginRoutes, ...userRoutes]随后 normalizeAllRoutes 会递归展开路由树子路由会与父路由路径拼接pathJoin(parentPath, route.path)并将嵌套路由扁平化为以路径为键的映射。这正是/products与/products/:seoName能共存、且层级路径被正确归一化的原因。而每个路由的getData则由 packages/react-static/src/static/getRouteData.js 在导出阶段被逐路由调用let data !!route.getData (await route.getData({ ...state, route })) data data || {}也就是说你在getRoutes中为每个路由配置的getData会在 HTML 导出时于 Node 进程内同步执行其结果被序列化为routeInfo.json并随页面一起产出。这也是本文开头强调必须为HttpLink配置node-fetch的原因——构建期这段client.query()确实运行在 Node 环境中。对照参考官方 basic 模板 packages/react-static/templates/basic/static.config.js 展示了同一模式只不过它用axios从 REST API 拉取数据并生成/blog与/blog/post/:id路由。Apollo 方案与之唯一的差别就是把axios.get换成client.query因此很容易迁移。混合模式构建时静态数据 客户端实时数据实际项目中经常需要同时使用两种数据获取方式。典型的诉求是构建时获取静态数据用于 SEO 优化的页面与感知性能提升特别是变化缓慢的数据电商场景中如商品名称、描述、图片客户端查询 API获取快速变化的数据如可售库存、实时价格以及执行 Mutation 数据变更如下单。下面演示在单个商品详情页/products/:seoName中如何同时使用构建期静态数据和客户端实时查询来更新库存或价格这类快速变化的属性import React from react import { useRouteData } from react-static import { Query } from react-apollo import GET_PRODUCT from ../graphql/getProduct export default function Product() { { /* STATIC DATA FROM THE BUILD */ } const { product } useRouteData() return ( div h1{product.name}/h1 p{product.shortDescription}/p img src{product.imageUrl} alt{product.name} / Query query{GET_PRODUCT} variables{{ seoName: product.seoName }} {({ loading, error, data }) { if (loading) return pLoading.../p if (error) return pError :(/p return ( div {/* LIVE DATA FROM THE QUERY */} pPrice: {data.product.price}/p pStock: {data.product.stock}/p /div ) }} /Query /div ) }注意原指南示例中import { withRouteData } from react-static与下方实际调用的useRouteData()不一致。以本仓库源码为准正确的导入应为import { useRouteData } from react-static该 Hook 定义于 packages/react-static/src/browser/hooks/useRouteData.js是 React Static 推荐的数据获取 Hookbasic 模板的 src/pages/blog.js 与 src/containers/Post.js 均采用此写法。useRouteData 的工作原理useRouteData的核心逻辑在 packages/react-static/src/browser/hooks/useRouteData.js它从全局的routeInfoByPath中取出当前路由对应的构建期数据如果发现该路由还没有可用数据shouldLoadData返回true则会通过prefetch触发数据加载并借助 React Suspense 挂起组件直到数据就绪否则直接返回getFullRouteData(routeInfo)中的全部数据。这意味着构建期写入页面的product名称、描述、图片在首屏立即可用无需等待任何请求需要实时刷新的价格、库存则由Query组件在客户端独立发起请求两者互不干扰。混合模式的一个关键约束构建期不允许 Suspense需要特别提醒的是混合模式下构建期渲染的组件不能 suspend。在 packages/react-static/src/static/exportRoute.js 中导出阶段对渲染错误做了显式拦截if (error.then) { error.message Components are not allowed to suspend during static export. Please make its data available synchronously and try again! }也就是说在生成静态 HTML 时页面组件使用的数据必须已经由getData/useRouteData在构建端同步提供即上方示例中的product而不能依赖客户端Query的异步结果——这正是把「静态数据产品信息放构建期、实时数据库存价格放客户端」这一职责切分的原因所在。构建端的数据通过 exportRoute.js 序列化进routeInfo.json并内联到 HTML 的window.__routeInfo脚本中浏览器水合时即可直接读取。构建/导出流程小结将 Apollo 方案放入 React Static 的整体导出流程见 packages/react-static/src/static/exportRoutes.js中看fetchSiteData(state)执行getSiteData获取全站共享数据fetchRoutes(state)执行getRoutes其中包含你对 Apollo Client 的查询调用得到完整路由树buildHTML(state)逐路由调用getData再次与 Apollo 交互可选、服务端渲染组件并输出静态 HTML 与routeInfo.json该阶段默认利用多核进行多线程导出maxThreads与exportRoutes.threadedplugins.afterExport(state)执行导出后钩子如 sitemap 插件生成站点地图。从源码结构packages/react-static/src/static/ 目录可以看出static.config.js中你编写的getRoutes、getData、getSiteData会被构建器在 Node 进程内依次调用——这解释了为什么「同一个 Apollo Client node-fetch」的模块可以同时服务于构建期与浏览器端。参考与延伸阅读指南原文docs/guides/apollo.md路由生成与归一化packages/react-static/src/static/getRoutes.js路由数据获取getData调用点packages/react-static/src/static/getRouteData.js客户端数据 HookuseRouteDatapackages/react-static/src/browser/hooks/useRouteData.js静态 HTML 导出与 Suspense 约束packages/react-static/src/static/exportRoute.js无 Apollo 的对照示例axios RESTpackages/react-static/templates/basic/static.config.js 与 packages/react-static/templates/basic/src/containers/Post.js配置项总览docs/config.md构建期数据获取更完整的说明见 docs/concepts.md赞分享前端开发工具【免费下载链接】react-static⚛️ A progressive static site generator for React.项目地址https://gitcode.com/gh_mirrors/re/react-static点击查看免费下载相关推荐CANN算子挑战赛江山赛区 CANN 算子挑战赛 江山赛区 大赛简介 CANN 算子挑战赛是华为算法挑战赛的子赛道江山赛区面向江苏、山东地域是 CANN 算子挑战赛的全国首场比赛CANN文档高性能计算xterm.js与GraphQL集成实时终端数据查询xterm.js与GraphQL集成实时终端数据查询 1. 痛点解析传统终端数据交互的三大瓶颈 在Web终端应用开发中开发者常面临以下挑战 数据同步滞后前端UI组件在 Create React App 项目中集成 Socket.IO从实时服务器到 React 客户端完整实战在 Create React App 项目中集成 Socket.IO从实时服务器到 React 客户端完整实战 导读 本文以 socket.io 仓库中的 e后端即时通讯WebSocket上一篇网页视频下载3步搞定VideoDownloadHelper视频下载插件完整上手指南下一篇VideoDownloadHelper怎么用三步搞定网页视频下载免费开源Chrome插件全攻略创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表