跳至主要內容

Relay Hooks 介紹

·6 分鐘閱讀

我們非常興奮地發布了 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 將 Suspense 用於其某些 API,但對於在 React 中使用 Suspense 進行數據獲取的支援、一般指南和要求仍未準備好,並且 React 團隊仍在為即將發布的版本定義此指南。當 Suspense 與 React 17 一起使用時,存在一些限制。

儘管如此,我們現在發布 Relay Hooks,是因為我們知道這些 API 正確地支援了即將發布的 React 版本。即使 Relay 的 Suspense 實作部分可能仍會變更,但 Relay Hooks API 本身是穩定的;它們已在內部廣泛採用,並且已在生產環境中使用了一年多。

請參閱 Suspense 相容性使用 Suspense 的載入狀態,以深入探討此主題。

從哪裡開始?

請查看入門指南遷移指南導覽

感謝

發布 Relay Hooks 不僅是 React 數據團隊的工作。我們要感謝幫助實現這一目標的貢獻者

@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, @rsmelo92, @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 hook 的想法源自該 repo 上的一個issue。感謝 @morrys 推動此專案,並在我們的開源社群中扮演如此重要的角色。

感謝您的協助,使這一切成為可能!