我们非常高兴地发布 Relay Hooks,这是迄今为止最开发者友好的 Relay 版本,并且 今天将其提供给 OSS 社区!Relay Hooks 是一组新的、经过重新思考的 API,用于使用 React Hooks 获取和管理 GraphQL 数据。
新 API 与现有的基于容器的 API 完全兼容。虽然我们建议使用 Relay Hooks 编写任何新代码,但将现有容器迁移到新 API 是可选的,基于容器的代码将继续工作。
尽管这些 API 是新发布的,但它们并非未经测试:重写的 Facebook.com 完全由 Relay Hooks 提供支持,自 2019 年年中以来,这些 API 一直是 Facebook 推荐的 Relay 使用方式。
此外,我们还发布了一个重写的 引导游览 和 更新的文档,这些文档提炼了我们自首次开发 Relay 以来在构建可维护、数据驱动的应用程序方面学到的最佳实践。
尽管我们还有很长的路要走,才能让 Relay 的入门像我们希望的那样容易,但我们相信这些步骤将使 Relay 开发者体验大幅提升。
发布了什么?
我们发布了 Relay Hooks,这是一组基于 React Hooks 的 API,用于处理 GraphQL 数据。我们还借此机会发布了其他改进,例如 fetchQuery
的更稳定版本以及使用 getDataID
自定义 Relay 中对象标识符的能力(如果您的服务器没有全局唯一的 ID,这将很有用)。
查看 发布说明 以获取已发布内容的完整列表。
Hooks API 的优点是什么?
新发布的 API 至少通过以下方式改善了开发人员体验
- 用于获取查询、使用片段加载数据、分页、重新获取、变异和订阅的基于 Hooks 的 API 通常需要更少的代码行,并且比等效的基于容器的解决方案具有更少的间接性。
- 这些 API 具有更完整的 Flow 和 Typescript 覆盖率。
- 这些 API 利用编译器功能来自动执行容易出错的任务,例如生成重新获取和分页查询。
- 这些 API 带有配置获取策略的能力,这使您能够确定应从存储中获取查询以及应进行网络请求的条件。
- 这些 API 使您能够在组件渲染之前开始获取数据,这是基于容器的解决方案无法实现的。这允许用户更快地看到数据。
以下示例展示了新 API 的一些优点。
使用不同的变量重新获取片段
首先,让我们看看如何使用 Hooks API 重新获取具有不同变量的片段
type Props = {
comment: CommentBody_comment$key,
};
function CommentBody(props: Props) {
const [data, refetch] = useRefetchableFragment<CommentBodyRefetchQuery, _>(
graphql`
fragment CommentBody_comment on Comment
@refetchable(queryName: "CommentBodyRefetchQuery") {
body(lang: $lang) {
text
}
}
`,
props.comment,
);
return <>
<CommentText text={data?.text} />
<Button
onClick={() =>
refetch({ lang: 'SPANISH' }, { fetchPolicy: 'store-or-network' })
}>
>
Translate
</Button>
</>
}
将其与等效的 基于容器的示例 进行比较。基于 Hooks 的示例需要更少的代码行,不需要开发人员手动编写重新获取查询,并且重新获取变量的类型已检查,并明确说明如果查询可以从存储中的数据获取,则不应发出网络请求。
在渲染组件之前开始获取数据
新 API 允许开发人员通过在组件渲染之前开始获取数据来更快地向用户显示内容。使用此方法预取数据在基于容器的 API 中是不可能的。考虑以下示例
const UserQuery = graphql`
query UserLinkQuery($userId: ID!) {
user(id: $userId) {
user_details_blurb
}
}
`;
function UserLink({ userId, userName }) {
const [queryReference, loadQuery] = useQueryLoader(UserQuery);
const [isPopoverVisible, setIsPopoverVisible] = useState(false);
const maybePrefetchUserData = useCallback(() => {
if (!queryReference) {
// calling loadQuery will cause this component to re-render.
// During that re-render, queryReference will be defined.
loadQuery({ userId });
}
}, [queryReference, loadQuery]);
const showPopover = useCallback(() => {
maybePrefetchUserData();
setIsPopoverVisible(true);
}, [maybePrefetchUserData, setIsPopoverVisible]);
return <>
<Button
onMouseOver={maybePrefetchUserData}
onPress={showPopover}
>
{userName}
</Button>
{isPopoverVisible && queryReference && (
<Popover>
<React.Suspense fallback={<Glimmer />}>
<UserPopoverContent queryRef={queryReference} />
</React.Suspense>
</Popover>
)}
</>
}
function UserPopoverContent({queryRef}) {
// The following call will Suspend if the request for the data is still
// in flight:
const data = usePreloadedQuery(UserQuery, queryRef);
// ...
}
在此示例中,如果查询无法从本地缓存中的数据获取,则当用户将鼠标悬停在按钮上时将启动网络请求。因此,当最终按下按钮时,用户将更快地看到内容。
相比之下,基于容器的 API 在组件渲染时启动网络请求。
Hooks 和 Suspense 用于数据获取
您可能已经注意到这两个示例都使用了 Suspense。
尽管 Relay Hooks 对某些 API 使用了 Suspense,但React 中对 Suspense 用于数据获取的支持、一般指南和使用要求仍然尚未准备好,React 团队仍在为即将发布的版本定义这些指南。在 React 17 中将 Suspense 与之结合使用时存在一些限制。
尽管如此,我们现在发布了 Relay Hooks,因为我们知道这些 API 正在朝着支持即将发布的 React 版本的正确方向发展。即使 Relay 的 Suspense 实现的部分内容可能仍然会发生变化,Relay Hooks API 本身是稳定的;它们已在内部广泛采用,并且已在生产环境中使用了一年以上。
查看 Suspense 兼容性 和 使用 Suspense 的加载状态 以更深入地了解此主题。
下一步做什么
感谢
发布 Relay Hooks 不仅仅是 React Data 团队的工作。我们要感谢使这一切成为可能的贡献者
@0xflotus, @AbdouMoumen, @ahmadrasyidsalim, @alexdunne, @alloy, @andrehsu, @andrewkfiedler, @anikethsaha, @babangsund, @bart88, @bbenoist, @bigfootjon, @bondz, @BorisTB, @captbaritone, @cgriego, @chaytanyasinha, @ckknight, @clucasalcantara, @damassi, @Daniel15, @daniloab, @earvinLi, @EgorShum, @eliperkins, @enisdenjo, @etcinit, @fabriziocucci, @HeroicHitesh, @jaburx, @jamesgeorge007, @janicduplessis, @jaroslav-kubicek, @jaycenhorton, @jaylattice, @JonathanUsername, @jopara94, @jquense, @juffalow, @kafinsalim, @kyarik, @larsonjj, @leoasis, @leonardodino, @levibuzolic, @liamross, @lilianammmatos, @luansantosti, @MaartenStaa, @MahdiAbdi, @MajorBreakfast, @maraisr, @mariusschulz, @martinbooth, @merrywhether, @milosa, @mjm, @morrys, @morwalz, @mrtnzlml, @n1ru4l, @Nilomiranda, @omerzach, @orta, @pauloedurezende, @RDIL, @RicCu, @robrichard, @rsmelo94, @SeshanPillay25, @sibelius, @SiddharthSham, @stefanprobst, @sugarshin, @taion, @thedanielforum, @theill, @thicodes, @tmus, @TrySound, @VinceOPS, @visshaljagtap, @Vrq, @w01fgang, @wincent, @wongmjane, @wyattanderson, @xamgore, @yangshun, @ymittal, @zeyap, @zpao 和 @zth。
开源项目 relay-hooks
使社区能够尝试 Relay 和 React Hooks,并且为我们提供了宝贵的反馈。useSubscription
挂钩的想法起源于该存储库中的 一个问题。感谢 @morrys 推动了这个项目,并在我们的开源社区中发挥了如此重要的作用。
感谢您帮助使这一切成为可能!