コンテンツにスキップ

Flutter のサーバー状態

サーバーデータに必要なのは、状態クラスをもう 1 つ増やすことではなく、キャッシュです。キャッシュは、すべての画面に同じコピーを渡します。読み込み中とエラーの状態を追跡し、古くなったデータを更新します。

Flutter アプリが表示するものの多くは、Todo のリスト、プロフィール、検索結果のページなど、サーバーから届きます。このデータは、アプリ自身が持つ状態とは違う振る舞いをします。

  • アプリのものではありません。サーバー上で、アプリに知らせずに変わります。
  • 共有されます。複数の画面が同じリストを表示し、その内容は一致している必要があります。
  • 遅れて届くか、まったく届きません。読み取りのたびに、読み込み中の状態とエラーの状態があります。
  • 古くなります。1 分前に取得したリストが、今は正しくないかもしれません。

選択中のタブなどのアプリの状態には、こうした問題はありません。

アプリの状態 サーバーデータ
変更する側 アプリのコード サーバー(いつでも)
正しい値を持つ場所 アプリ どこか別の場所
届くタイミング すぐ 遅れて、または届かない
古くなるか いいえ はい

サーバーデータをアプリの状態と一緒に管理すると、キャッシュを自分で書くことになります。リポジトリ内のキャッシュ、画面ごとの読み込みフラグ、更新メソッド、書き込みのたびの無効化、2 つの画面が同時に要求したときのルールです。

Fuery はサーバーデータをキーに紐づけて、1 つのキャッシュに保持します。

final todosQuery = Query(
queryKey: ['todos'],
queryFn: (_) => api.getTodos(),
);

この 1 つの定義から、次のものが得られます。

  • キーごとに 1 つのコピー:['todos'] を使うすべての画面が、同じキャッシュエントリを読み取ります。
  • 一度に 1 つのリクエスト:取得の実行中に要求した画面は、そのリクエストを共有します。
  • 新鮮(fresh)から古い(stale)へ:データは staleTime の間だけ新鮮です(デフォルトはゼロなので、届いた時点で古くなります)。
  • 古いデータは画面に残る:Fuery がバックグラウンドで再取得している間も、画面は古いデータを表示し続けます。
  • 自動で再取得:画面が古いデータを使い始めたときと、アプリがフォアグラウンドに戻ったときに、Fuery は古いデータを再取得します。接続状態のソースを設定すると、ネットワークに再接続したときにも再取得します(ネットワークに再接続したとき)。
  • 書き込みの後に再取得:ミューテーションの後で ['todos'] を無効化すると、Fuery が画面上のリストを再取得します。
  • 読み込み中とエラーの状態がデータと一緒に届く:結果には status、error、isRefetching などのフラグが含まれます。そのため、画面は状態を自分で追跡せず、結果から読み取ります。
  • 使われないデータはメモリから削除される:どの画面も使っていないデータを、ガベージコレクション時間の gcTime(デフォルトは 5 分)が過ぎると、Fuery がメモリから削除します。永続化されたデータはデバイスに残ります。

キャッシュされたデータの各段階と、各段階が終わる条件は、クエリのライフサイクルにまとめています。

キャッシュはウィジェットツリーの一部ではなく、普通の Dart オブジェクトです。同じクエリが次の 3 か所で動きます。

  • QueryBuilder が描画する
  • Cubit が todosQuery.observe() の stream をリッスンする
  • スクリプトが client.query(todosQuery) を await する

Fuery は、すでに使っている状態管理を置き換えません。Cubit と Bloc の中でクエリを使う方法は、Bloc と Cubitで紹介しています。

  • キャッシュのしくみ:定義、クライアント、オブザーバー、キャッシュされたデータのライフサイクル
  • はじめに:Fuery のインストールと、最初のリクエストのキャッシュ
  • クエリ:キー、鮮度、オプション
  • デモを試す:ブラウザーで動くサンプルアプリ(devtools 付き)