mcpField
R
riverpod-faq-and-practices

riverpod-faq-and-practices

github.com/serverpod開発1084 回インストール34 週間前に更新
リポジトリ

riverpod-faq-and-practices について

Flutter 開発者向けの Riverpod リファレンススキルです。プロバイダーのライフサイクル、Widget との連携、状態の配置、よくある問題への指針をまとめています。

主な機能

  1. 01ref.refresh と ref.invalidate の説明
  2. 02Ref と WidgetRef の使い分け
  3. 03プロバイダー初期化の実践方法
  4. 04ローカル状態と共有状態の区別
  5. 05riverpod_lint の活用指針

活用シーン

  1. 01ユーザー操作後の更新方法の選択
  2. 02await 後の安全な ref 使用
  3. 03状態をプロバイダーに置くかの判断
  4. 04プロバイダー定義の一般的な問題の確認

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/serverpod/skills-registry --skill riverpod-faq-and-practices

インストール後、Claude Code で/riverpod-faq-and-practicesを入力して読み込まれたか確認します。

詳細

Riverpod — FAQ とベストプラクティス

FAQ

ref.refresh と ref.invalidate の違い

ref.refresh = ref.invalidate + ref.read:プロバイダーを無効化し、新しい値を返します。新しい値が必要ない場合(例:「ユーザーが引っ張って更新したときに再計算する」)は invalidate を使います。結果がすぐに必要な場合は refresh を使います。invalidate だけを実行した場合、再計算は次のフレーム、またはプロバイダーが次に読み取られたときに行われます。refresh は読み取りを行うことで、即時の再計算を強制します。

Ref と WidgetRef の間に共通のインターフェースがないのはなぜですか?

Ref(プロバイダー内)と WidgetRef(ウィジェット内)は、両方に条件付きで依存するコードを書かないよう、意図的に分けられています。両者には微妙な違いがあり、混在させるとエラーが発生しやすくなります。Ref を優先してください。ロジックを Notifier に置き、UI から ref.read(notifierProvider.notifier).yourMethod() を呼び出します。このメソッドでは Notifier の Ref を使います。

StatelessWidget ではなく ConsumerWidget を使うのはなぜですか?

InheritedWidget(ひいては BuildContext)では、ref.listen のような「変更時」のリスナーをサポートできず、ウィジェットがリスナーを停止するタイミング(auto-dispose や family に必要)も把握できません。また、GlobalKeys を使用する場合など、ライフサイクルに関する癖もあります。これらの機能のために、Riverpod には BuildContext に紐づかない Ref が必要です。そのため、ConsumerWidget(および Consumer)が Ref を提供します。

hooks_riverpod が flutter_hooks をエクスポートしないのはなぜですか?

各パッケージを独立してバージョン管理できるようにするためです。一方の破壊的変更によって、もう一方も変更を余儀なくされることがありません。

すべてのプロバイダーを一度にリセットするには?

すべてのプロバイダーをリセットする API はありません。これはアンチパターンと見なされています。「ログアウトして状態をクリアする」には、現在のユーザーに依存するプロバイダーでユーザープロバイダーを ref.watch します。ユーザーがログアウトすると、そのプロバイダーが変更され、依存するプロバイダーが再計算またはクリアされます。リセットされるのはユーザーに依存する状態だけで、それ以外は保持されます。

「ウィジェットのアンマウント直前またはアンマウント後に ref を使用するのは安全ではありません」

これは(または「No ProviderScope found」は)、破棄される可能性があるウィジェットで await の後に ref を使用すると発生します。await の後は、ref を使用する前に if (!context.mounted) return; を確認してください(BuildContext と同じパターンです)。


やるべきこと/避けるべきこと

ウィジェットでプロバイダーを初期化しない

プロバイダーは自分自身を初期化する必要があります。initState から ref.read(provider).init() のような呼び出しをしないでください。初期化がユーザー操作(例:ナビゲーション)に依存する場合は、その操作から(例:Navigator.push の前に onPressed で)トリガーしてください。

一時的な状態にプロバイダーを使わない

プロバイダーは 共有するビジネス状態 に使い、選択中のタブ/項目、フォームの状態(画面を離れる/戻るときにリセットすべきもの)、アニメーション、コントローラーのような状態(例:TextEditingController)には使わないでください。ウィジェット内のローカルな状態には flutter_hooks またはローカル状態を使います。「選択中の項目」をグローバルプロバイダーに保存すると、戻る操作が壊れることがあります(例:/books/21 から戻ると /books/42 を表示すべきなのに、プロバイダーには 21 が保持されたままになる)。

プロバイダーの初期化中に副作用を実行しない

プロバイダーは「読み取り」操作を表す必要があります。フォームの送信など、「書き込み」操作を実行するためにプロバイダーの build を使わないでください。副作用が実行されなかったり、重複して実行されたりする可能性があります。副作用の読み込み中/エラー状態には mutations(riverpod-mutations を参照)を使います。

ref.watch/read/listen では静的に判明しているプロバイダーを優先する

provider がトップレベルの final(またはその他の方法で静的に判明しているもの)である場合は、ref.watch(provider) を使います。静的解析と riverpod_lint が機能するよう、プロバイダーをパラメーターとして渡してから監視する方法は避けてください。

プロバイダーを動的に作成しない

プロバイダーは トップレベルの final 変数として定義してください。クラス内やインスタンスフィールドとして作成しないでください。メモリーリークやサポートされていない動作につながる可能性があります。クラス内の static final は使用できますが、コード生成ではサポートされていません。

これらのベストプラクティスの多くを徹底するには、riverpod_lint(riverpod-getting-started を参照)を有効にしてください。

コメント