LoginSignup
10
1

More than 1 year has passed since last update.

【Flutter/Riverpod】画面遷移時の引数をProviderScopeのoverrideで設定する

Last updated at Posted at 2022-12-21

この記事は ウェブクルー Advent Calendar 2022 22日目の記事です。
昨日は @tatsuyanamiki さんの「PageSpeed Insightsで指摘されがちな改善提案と対策について」でした。

はじめに

ウェブクルーでは、今年度よりアプリ開発準備室という、モバイルアプリ開発のスキル向上や、
モバイルアプリ開発組織の拡大に向けたナレッジ構築、企画開発をしていくチームを発足しました。

その中で採用した技術の1つに、モバイルアプリフレームワークの Flutter があります。
今回は、そのFlutterアプリ開発のスキル向上の際に培った技術の中で、
Riverpodの機能を活用した画面遷移で試した方法を記事にまとめようと思います。
なお、Flutter環境構築やRiverpodについての説明は割愛します。

ページ間で引数を渡す

Flutterの画面遷移で調べていて、よく見かけた引数を渡す実装は、
下記の実装例のようにページ間で引数を渡していることが多かったです。

文字列 testId を画面遷移時に渡す場合:

画面遷移先では testId を受け取り、
受け取った testId を使ってViewModelなどに用意した関数を実行します。

class TestPage extends HookConsumerWidget {
  final String testId;
  const TestPage({Key? key, required this.testId}) : super(key: key);

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final state = ref.watch(testViewModelProvider);
    final testViewModel = ref.watch(testViewModelProvider.notifier);

    useEffect(() {
      Future(() {
        testViewModel.fetchByTestId(testId);
      });
      return null;
    }, []);
    // ~~~ 省略 ~~~
  }
}

画面遷移元では、onTaponPressed の処理で引数 testId を渡しています。

Navigator.of(context).push(
  MaterialPageRoute(
    builder: (context) {
      return TestPage(testId: data.testId);
    },
  ),
);

ProviderScope override

上記の実装例だと、画面遷移元から渡された testId
画面遷移先のMVVMでいうViewから引き回して操作するような実装になっています。
引数の数が増えたり呼び出す関数が増えると、View内の実装や定義も煩雑になってきます。

そこで、 ProviderScopeoverride を活用した実装です。

ProviderScopeoverride を活用すると、
ページ間で引数を渡すことなく、 Provider を上書きして引数を設定することができます。

Provider.family

ProviderScopeoverride を活用する上で、
Provider.family についても知っておく必要があります。

Provider.family 修飾子を付けて Provider を作成すると、
Provider に引数を設定することができるようになります。

この Provider.familyoverride することで、
ページ間で引数を渡すことなく、 Provider に引数を渡すことができます。

実装例

ProviderProvider.family を用意します。
実装例ではMVVMでいうViewModelにあたる部分に実装しています。

final testViewModelProviderFamily =
  StateNotifierProvider.autoDispose.family<TestViewModel, AsyncValue<TestState>, String>(
    (ref, testId) => TestViewModel(testId, ref: ref));

final testViewModelProvider =
  StateNotifierProvider.autoDispose<TestViewModel, AsyncValue<TestState>>(
    (ref) => throw UnimplementedError());

class TestViewModel extends StateNotifier<AsyncValue<TestState>> {
  final AutoDisposeStateNotifierProviderRef _ref;
  final String testId;

  TestViewModel(this.testId, {required AutoDisposeStateNotifierProviderRef ref})
    : _ref = ref,
      super(const AsyncLoading());
  // ~~~ 省略 ~~~
}

画面遷移元の onTaponPressed の処理で Provider.familyoverride します。
この際、ページ間で引数を渡す必要はないので、 child: const TestPage() となります。

Navigator.of(context).push(
  MaterialPageRoute(
    builder: (context) => ProviderScope(
      overrides: [
        testViewModelProvider
          .overrideWithProvider(testViewModelProviderFamily(data.testId))
      ],
      child: const TestPage()
    )
  )
)

画面遷移後は下記のように参照できます。
画面遷移前の ProviderScopeoverride で引数 testId を渡しているので、
画面遷移後のページ側では引数を意識することなく記述ができます。

class TestPage extends HookConsumerWidget {
  const TestPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final state = ref.watch(testViewModelProvider);
    final testViewModel = ref.watch(testViewModelProvider.notifier);

    useEffect(() {
      Future(() {
        testViewModel.fetchByTestId();
      });
      return null;
    }, []);
    // ~~~ 省略 ~~~
  }
}

おわりに

ProviderScopeoverride を活用することで、
画面遷移時に引数を引き回すことなく、実装する方法について簡単にまとめました。
Provider.family の引数には、文字列以外にも独自に実装したクラスも渡せるので、
複数の引数を1つのクラスにまとめて設定することも可能です。

現在のアプリ開発準備室は、Flutterを活用した複数のアプリの企画開発と並行して、
実際にリリースしたモバイルアプリの運用フェーズに進みつつあります。
モバイルアプリ開発に限らず、企画で挙がった内容に併せて、Web版やAPIの開発も進めていきます。

明日は、 @ee4839 さんです。
よろしくお願いします。

ウェブクルーでは一緒に働いていただける方を随時募集しております。
お気軽にエントリーくださいませ。
https://www.webcrew.co.jp/recruit/

10
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
1