本文へスキップ

Understanding Relay Fetch Policies and Suspense

Understanding Relay Fetch Policies and Suspense

Hello, my name is Luiz and I'm a software engineer based in Brazil. Today, I’m going to explain how react-relay works with React's Suspense API, how various fetchPolicy options can make your component suspend, and what I typically use for each scenario. So, without any further ado, let's get started.

What Is Suspense?

Suspense is a powerful API provided by React to handle asynchronous rendering. It allows you to define a fallback UI (like a loader or spinner) that is displayed while a component waits for asynchronous data—such as data fetched from an API—to be ready.

Relay leverages Suspense to make data fetching seamless. When you use hooks like useLazyLoadQuery or usePreloadedQuery, if the data isn't available immediately (because it's still being fetched from the network), the component will "suspend" its rendering. During this suspension, React displays the fallback specified in the Suspense boundary.

Here's an example of how Relay and Suspense work together:

Relay and Suspense ExampleRelay Suspense Example

In the example above, the ProfilePage component uses useLazyLoadQuery to request posts. While that query is fetching data, it triggers Suspense to display a loading fallback until the data is ready. Notably, the fetchPolicy used is network-only, which means a fresh network request is made regardless of the local cache status—thereby ensuring that Suspense is engaged while waiting for the data.

A common question is: Why is Suspense placed above the component in the tree rather than inside the component's return?
The answer is that Suspense must wrap around the parts of your component that perform data fetching (e.g., hooks like useLazyLoadQuery or usePreloadedQuery). This setup allows Suspense to effectively manage the asynchronous state and provide a proper fallback UI when needed.

Fetch Policies and How They Can "Suspend" the Component

Relay offers several fetch policies to control how data is fetched and cached. Here’s a quick overview:

  • store-or-network (DEFAULT)
    • Behavior: Reuses locally cached data, and sends a network request only if some of the required data is missing or stale.
    • Usage: If the query is fully cached, no network request is made. However, if some data is missing or if a refetch occurs due to changed variables, Suspense may be triggered to fetch the missing data.
  • store-and-network
    • Behavior: Uses locally cached data immediately, while simultaneously sending a network request to update the cache.
    • Usage: This policy is ideal when you want to show cached data for a snappy UI but still ensure that the data is up-to-date by refreshing it in the background.
  • network-only
    • Behavior: Ignores any locally cached data and always makes a network request.
    • Usage: Use this when you require the most current data. Because it bypasses the cache entirely, it forces the component to suspend until the network request completes.
  • store-only
    • Behavior: Only uses locally cached data and never initiates a network request.
    • Usage: This is useful when you are confident that the required data is already in the cache, or if you have an external mechanism for data fetching. No Suspense will be triggered since no network request is made.

Choosing the Right Fetch Policy

The choice of fetch policy largely depends on your application's data freshness needs and user experience considerations:

  • store-or-network: Ideal for scenarios where you want to take advantage of local caching for faster render times but still need to fetch missing or outdated data when necessary.
  • store-and-network: Best when you want to show cached content immediately, yet update the data in the background to ensure users see the latest information.
  • network-only: Perfect for use cases where data freshness is paramount and you prefer to always fetch new data, accepting the delay while the component suspends.
  • store-only: Suitable for read-only views or when you have pre-fetched data elsewhere, ensuring that no unexpected network calls are made.

A Practical Example

Imagine you’re building a user profile page that must always display the latest user data. Here’s how you might structure your component using network-only to ensure data freshness:

import React, { Suspense } from "react";
import { useLazyLoadQuery, graphql } from "react-relay";

const UserProfileQuery = graphql`
  query UserProfileQuery($id: ID!) {
    user(id: $id) {
      name
      email
      profilePicture
    }
  }
`;

function UserProfile({ userId }) {
  // Using network-only to always fetch the latest data
  const data = useLazyLoadQuery(
    UserProfileQuery,
    { id: userId },
    { fetchPolicy: "network-only" },
  );

  return (
    <div>
      <img src={data.user.profilePicture} alt="Profile" />
      <h1>{data.user.name}</h1>
      <p>{data.user.email}</p>
    </div>
  );
}

export default function ProfilePage({ userId }) {
  return (
    <Suspense fallback={<div>Loading profile...</div>}>
      <UserProfile userId={userId} />
    </Suspense>
  );
}

In this example:

  • The UserProfile component always fetches fresh data due to the network-only policy.
  • The Suspense boundary in the ProfilePage component ensures that a fallback UI (Loading profile...) is displayed while the data is being loaded.

Conclusion

Integrating react-relay with React's Suspense API provides a clean and efficient way to handle asynchronous data fetching. By understanding and leveraging the various fetch policies, you can finely tune your component’s behavior to balance performance with data freshness:

  • store-or-network is great for harnessing the power of the cache while still accommodating dynamic data needs.
  • store-and-network allows for an immediate UI response paired with background data updates.
  • network-only ensures your users always see the most current data, at the cost of suspending the component until the data is retrieved.
  • store-only is perfect for scenarios where data is already available locally and no additional network overhead is desired.

I hope this article has provided you with a clear understanding of how Relay's fetch policies interact with Suspense, and how to choose the right strategy for your application’s needs. Experiment with these techniques to see which approach works best in your development workflow, and happy coding!

Profile picture
Luiz Fernando - シニアソフトウェアエンジニア

読んでくれてありがとう!

この記事を楽しんで読んでいただければ幸いです。ご質問やご意見がございましたら、下記のソーシャル メディアからお気軽にご連絡ください。良い一日をお過ごしください。

Carousel imageCarousel imageCarousel imageCarousel imageCarousel image
次へ / 良い会話から始めましょう

大きなアイデア。
Little Luiz.

実現したいプロダクト、強くしたいチーム。一緒に何ができるか、話してみませんか。

道を選ぶ
01Freelance / Products

プロジェクトの相談

フリーランスでの協業、プロダクト開発、技術的な課題。

  • プロダクトの発見からリリースまで
  • ウェブ、モバイル、バックエンド開発
  • 明確なスコープと直接の協業
一緒につくりましょう
02Hiring / Teams

チームへの採用

エンジニアの採用と長期的な機会。

  • シニアフルスタックエンジニアリング
  • プロダクトの視点と技術的な責任
  • 分散チームでの経験
チームへの採用相談
03Résumé / Versions

履歴書を見る

汎用エンジニアリング、ヘルステック、フィンテックなど、用途別のバージョン。

  • 6つの特化バージョン
  • 印刷用PDFエクスポート
  • 役割ごとに更新
履歴書を見る
luizepauloxd@gmail.com

メールをご希望ですか?直接送るか、こちらで下書きを作成できます。

考えていることを教えてください。

© 2026 Luiz Fernando 意図と、少しの好奇心を込めて。ページの先頭へ