派生字段
除了对客户端状态进行建模之外,中继解析器还允许你定义字段,这些字段是其他字段的纯函数。这些字段称为派生字段,可以在任何类型上定义,无论它是在服务器上还是客户端上定义。
对于全局相关数据,解析器与其他解决方案(如 React Hooks)相比具有一些优势。
- 全局记忆化 - 中继解析器会自动记忆派生字段。与钩子不同,此缓存由应用程序中的所有组件共享,因此,如果两个兄弟组件都读取同一个字段,则该计算只会执行一次。
- 高效更新 - 如果你的派生解析器重新计算但得出相同的值,中继可以避免重新渲染读取该字段的组件。
- 可组合 - 派生字段可以与其他派生字段组合,允许你构建复杂的但显式的计算图。
- 可发现 - 图中的值可以通过 GraphQL 模式发现,因此更容易被发现并重复使用,而不是重新发明。
- 有文档 - GraphQL 的字段文档和结构化弃用模型使你能够轻松了解字段的用途及其预期用途。
定义派生解析器
派生解析器与其他解析器类似,不同之处在于它们读取 GraphQL 数据,而不是从父模型类型计算。派生解析器通过定义一个“根片段”来读取 GraphQL 数据,该片段是在字段的父类型上定义的 GraphQL 片段。
根片段使用 @rootFragment
文档块标签和片段名称来定义。这告诉中继向解析器函数传递该片段的片段键。然后可以使用从 relay-runtime
导入的 readFragment
来读取片段数据。
- 文档块
import {readFragment} from 'relay-runtime';
/**
* @RelayResolver User.fullName: String
* @rootFragment UserFullNameFragment
*/
export function fullName(key: UserFullNameFragment$key): string {
const user = readFragment(graphql`
fragment UserFullNameFragment on User {
firstName
lastName
}
`, key);
return `${user.firstName} ${user.lastName}`;
}
信息
中继会跟踪从片段读取的所有值,并在这些值中的任何值发生变化时自动重新计算解析器。
组合
派生解析器的一个强大功能是它们可以读取其他中继解析器字段。这意味着你可以定义一个派生解析器,它将服务器数据、客户端数据甚至其他派生解析器组合在一起。这使你能够构建复杂的但显式的计算图。
/**
* @RelayResolver CheckoutItem.isValid: Boolean
* @rootFragment CheckoutItemFragment
*/
export function isValid(key): boolean {
const item = readFragment(graphql`
fragment CheckoutItemFragment on CheckoutItem {
product {
price
}
quantity
}
`, key);
return item.product.price * item.quantity > 0;
}
/**
* @RelayResolver ShoppingCart.canCheckout: Boolean
* @rootFragment ShoppingCartFragment
*/
export function canCheckout(key): boolean {
const cart = readFragment(graphql`
fragment ShoppingCartFragment on ShoppingCart {
items {
isValid
}
}
`, key);
return cart.items.every(item => item.isValid);
}
将参数传递给你的 @rootFragment
如果派生解析器的根片段中的字段需要参数,则可以通过向文档块标签添加 @arguments
标签来传递参数。@argument
标签采用参数的名称和参数的类型。参数类型必须是有效的 GraphQL 输入类型。有关参数和解析器的更多信息,请参阅 字段参数。