URQL
约 4 分钟阅读
- FormidableLabs/urqlGitHubFormidableLabs/urqlFormidableLabs/urql · 流处理实现基于 kitten/wonka · 优势 · 支持泛化缓存 · Schema 感知 · 开启后支持部分结果返回 - 请求的字段未被缓存但是是 nullable 则先返回 - 因为不影响语义笔记:URQL
- 流处理实现基于 kitten/wonkaGitHubkitten/wonka
- 优势
- 支持泛化缓存
- Schema 感知
- 开启后支持部分结果返回 - 请求的字段未被缓存但是是 nullable 则先返回 - 因为不影响语义
- 页面切换数据显示更顺畅
- stale 查询 - @urql/exchange-request-policy
- 支持多框架 - @urlql/core, urql -> react-urql, preact, next, vue, svelte
- 参考
- RFC: Fragment Suspense boundaries in React bindings #1408GitHub Issueurql-graphql/urql#1408
- useQuery 的 context 确保不要变 - useMemo
- 否则会导致重新请求 - 可能无限循环渲染
- 默认全局 opt-in Suspense
- createClient 开启 suspense 则默认认为在服务端 - 所有查询开启 suspense
- useURQL 的 context 可控制关闭 suspense
- 对于只希望单次查询 suspense 只能封装现有接口
- #2235GitHuburql-graphql/urql/discussions/2235
- 自定义 scalar 处理
- 不支持 batch #800GitHub Issueurql-graphql/urql#800
npm add urql @urql/{core,devtools,exchange-graphcache,exchange-retry,exchange-multipart-fetch}依赖包urqlnpm 包urqlNPM@urql/{core,devtools,exchange-graphcache,exchange-retry,exchange-multipart-fetch}npm 包@urql/{core,devtools,exchange-graphcache,exchange-retry,exchange-multipart-fetch}NPM
import { SubscriptionClient } from 'subscriptions-transport-ws';
import { createClient as createSubscriptionClient } from 'graphql-ws';type ExchangeIO = (Source<Operation>) => Source<OperationResult>;
type Exchange = ExchangeInput => ExchangeIO;Note
- 默认有 Document Caching - 适用于高度依赖静态数据的站点
- 缓存 key 为
hash(query,variables) - 根据 mutation 返回类型进行失效
- 如果返回空 list, 则不会包含
__typename, 此时无法失效 - 可在上下文添加 additionalTypenames
- 缓存 key 为
- exchange - 扩展点 - 默认 dedupExchange, cacheExchange, fetchExchange
- 类似 apollo 的 link - 但更通用
请求策略
| RequestPolicy | Desc |
|---|---|
| cache-first | 默认 默认返回 cache 结果,不存在则请求 |
| cache-and-network | 先返回 cache 结果,也请求更新 |
| network-only | 忽略缓存,直接发起请求 |
| cache-only | 返回缓存或者 null |
exchanges
| exchange | desc |
|---|---|
| @urql/exchange-graphcache | 提供泛化图缓存 |
| @urql/exchange-retry | 重试失败请求 |
| @urql/exchange-execute | 本地模拟执行,用于测试或服务端 |
| @urql/exchange-multipart-fetch | 文件上传 |
| @urql/exchange-persisted-fetch | 基于 hash 查询,避免发送 query |
| @urql/exchange-request-policy | 缓存失效和更新,将 cache-first 和 cache-only 上升为 cache-and-network |
| @urql/exchange-auth | 请求添加授权信息,例如 JWT |
| @urql/exchange-refocus | 窗口获取焦点时重新发起请求 |
@urql/exchange-graphcache
- Normalized Caching - 泛化缓存
- 缓存 key 为
__typename:id - 会缓存字段和关系
- 可根据类型自定义缓存 key
- 无 key 的结构作为嵌入数据依附在上级文档
- 缓存 key 为
- Local Resolver - 本地解析
- 提供 resolvers 直接在客户端处理请求
cache.readQuery({ query: Todos, variables: { from: 0, limit: 10 } });
// readFragment 只支持 DocumentNodes
cache.readFragment(
gql`
fragment _ on Todo {
id
text
}
`,
{ id: 1 },
);
// 检测所有字段
cache.inspectFields({
__typename: 'Todo',
id: args.id,
});// 基于 offset 和 limit 分页
import { simplePagination } from '@urql/exchange-graphcache/extras';
//
import { relayPagination } from '@urql/exchange-graphcache/extras';
cacheExchange({
keys: {
// 自定义 key
Item: (data) => data.uuid,
// 显性移除 key
Image: () => null,
},
// 本地 resolve
// 适用于转换字段类型,模仿服务端请求,减少实际请求
resolvers: {
// 类型
Query: {
// 集成分页能力
// mergeMode=inwards
todos: relayPagination(),
// { todo(id: 1) { id } } 读取 { todos { id } } 的缓存
todo(parent, args, cache, info) {
// 等同于返回缓存 key
// cache.keyOfEntity({ __typename: 'Todo', id: args.id }),
return { __typename: 'Todo', id: args.id };
},
},
Todo: {
// 转换字段类型
updatedAt: (parent, args, cache, info) => {
// 也可以访问当前对象上数据 - cache.resolve(info.parentKey)
// parent.updatedAt || cache.resolve(parent, "createdAt")
// new Date(cache.resolve(parent, "updatedAt")),
return new Date(parent[info.fieldName]);
},
},
},
// 手动更新
updates: {
Mutation: {
// add 过后将返回结果添加到 查询列表
addTodo(result, args, cache, info) {
const query = gql`
{
todos {
id
}
}
`;
cache.updateQuery({ query }, (data) => {
data.todos.push(result.addTodo);
return data;
});
},
// 移除 todo 后更新受影响的 list 查询
removeTodo(_result, args, cache, _info) {
const TodoList = gql`
query (skip: $skip) {
todos(skip: $skip) { id }
}
`;
const fields = cache.inspectFields('Query')
.filter(field => field.fieldName === 'todos')
.forEach(field => {
cache.updateQuery(
{
query: TodoList,
variables: { skip: field.arguments.skip },
},
data => {
data.todos = data.todos.filter(todo => todo.id !== args.id);
return data;
}
});
});
},
},
},
// 乐观更新 - 模仿服务端更新行为
// 当服务端返回后更新会丢弃
optimistic: {
favoriteTodo: (variables, cache, info) => ({
__typename: 'Todo',
id: variables.id,
favorite: true,
}),
},
});relayPagination
- Resolver
- 基于 relay 的 connection 进行分页数据合并
- 支持 first+last
- 支持 before, after
- mergeMode - 合并模式
- inwards - 默认 - 往后合并
- outwards - 往前合并
- 参数变化会重置 - 忽略 first, last, after, before
Version
URQL v4
- 没有 defaultExchanges
- 之前为 [dedupExchange, cacheExchange, fetchExchange]
- fetch
- 支持 multipart/mixed, text/event-stream
@urql/exchange-multipart-fetch- 合并到 core
dedupExchange- 默认行为
- core
- 不再依赖 graphql
- bundle 部分 graphql 内容: parse, print, GraphQLError
- urql v4 Major ReleasesGitHub Issueurql-graphql/urql#3114
FAQ
URQL vs Apollo
- URLQ
- 更小更灵活
- 支持提供 schema 实现更多功能
- 支持 offline
- 支持 window focus 触发请求
- 缓存为可选组件
- vs Apollo
production 构建后 urql 返回 null
起因是 gqlgen 不支持 fragment 里包含 alias,不会返回字段,urql 检测少字段认为 cache miss 返回 null。
- 99designs/gqlgen#1271GitHub Issue99designs/gqlgen#127199designs/gqlgen 是什么? · 基于生成的 GraphQL 引擎 · Schema first - 需要 DSL 定义 GraphQL Schema · 类型安全 · 支持 Plugin - 修改配置, 生成代码 · 缺点 · 库代码质量一般笔记:gqlgen
- FormidableLabs/urql#1557GitHub IssueFormidableLabs/urql#1557
Cannot update a component while rendering a different component
- FormidableLabs/urql#1382GitHub IssueFormidableLabs/urql#1382
关联信息
反向链接、本文链接的其他页面和外部资料。
反向链接
- GraphQL Awesome笔记 · urql
WebUI · graphql/graphiql · graphql/graphql-playground · https://www.graphqlbin.com/v2/new · graphql-kit/graphql-voyager · interactive graph
参考资料
GitHub12 条
- 0no-co/graphql.webgithub.com/0no-co/graphql.web
- 99designs/gqlgen#1271github.com/99designs/gqlgen/issues/1271
- clentfort/urql-custom-scalars-exchangegithub.com/clentfort/urql-custom-scalars-exchange
- clentfort/urql-custom-scalars-exchange#27github.com/clentfort/urql-custom-scalars-exchange/pull/27
- FormidableLabs/urqlgithub.com/FormidableLabs/urql
- FormidableLabs/urql#1382github.com/FormidableLabs/urql/issues/1382
- FormidableLabs/urql#1557github.com/FormidableLabs/urql/issues/1557
- kitten/wonkagithub.com/kitten/wonka
- urql-graphql/urql/discussions/2235github.com/urql-graphql/urql/discussions/2235
- urql-graphql/urql#1408github.com/urql-graphql/urql/issues/1408
- urql-graphql/urql#3114github.com/urql-graphql/urql/issues/3114
- urql-graphql/urql#800github.com/urql-graphql/urql/issues/800
其他外链1 条
- formidable.com/open-source/urql/docs/comparisonformidable.com/open-source/urql/docs/comparison