我們非常興奮地發布 Relay Hooks,這是 Relay 有史以來對開發人員最友善的版本,並且今天將其提供給開放原始碼社群!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 的想法源自該儲存庫上的一個 issue。感謝 @morrys 驅動此專案,並在我們的開放原始碼社群中扮演如此重要的角色。
感謝您幫助實現這一切!