我們非常興奮地發布了 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 推動此專案,並在我們的開源社群中扮演如此重要的角色。
感謝您的協助,使這一切成為可能!