Slide 1

Slide 1 text

チームで採用しているriverpodを使った Flutterのアーキテクチャとriverpod v1.0.0 b4tchkn Flutter x Kotlin Multiplatform by CyberAgent #4 2021/08/06 #ca_flutter_kmm

Slide 2

Slide 2 text

About me Kakeru Nakabachi batch(@b4tchkn) 2

Slide 3

Slide 3 text

今日のゴール ● ちょっとこの部分参考にできるかも ● riverpodで状態管理いいかも ● CAもFlutterで色々やってるんだな👀 3

Slide 4

Slide 4 text

アジェンダ ● riverpodの簡単な紹介 ● チームのFlutterプロジェクトアーキテクチャ ● riverpod使用ルールについて 4

Slide 5

Slide 5 text

riverpod 5

Slide 6

Slide 6 text

● もともとあった、Providerという状態管理ライブラリの問題点を解消したやつ ● DIもこれで実現できる ● テスタブルなコードを保証してくれる ● 最近 v1.0.0に乗り換え ● hooks_riverpod ● flutter_riverpod ● riverpod https://riverpod.dev/docs/getting_started/ riverpod 6

Slide 7

Slide 7 text

● もともとあった、Providerという状態管理ライブラリの問題点を解消したやつ ● DIもこれで実現できる ● テスタブルなコードを保証してくれる ● 最近 v1.0.0に乗り換え ● hooks_riverpod ● flutter_riverpod ● riverpod https://riverpod.dev/docs/getting_started/ riverpod 7

Slide 8

Slide 8 text

hooks_riverpod flutter_hooksと併用する使い方 HookConsumerWidgetを使って中でref.watchなど便利メソッドが呼べる 8

Slide 9

Slide 9 text

hooks_riverpod 公式にも載ってる簡単なサンプル 9

Slide 10

Slide 10 text

hooks_riverpod riverpodを使うプロジェクトではAppを ProviderScopeでラップする 10

Slide 11

Slide 11 text

hooks_riverpod Stringを配るProvider 11

Slide 12

Slide 12 text

hooks_riverpod ProviderをWidget内で監視 12

Slide 13

Slide 13 text

hooks_riverpod riverpod v1.0.0での割と大きな変更点 13

Slide 14

Slide 14 text

チームのFlutterアーキテクチャ 14

Slide 15

Slide 15 text

全体像 15 UI State Domain Data

Slide 16

Slide 16 text

全体像 16 UI State Domain Data

Slide 17

Slide 17 text

● Service ○ DioとRetrofitを使った RemoteDataSource ○ 定義したabstract class(interface)から実 際にリクエストするコードを生成 ● Database ○ SharedPreferencesを使った LocalDataSource ○ Key - Valueでデータを永続化 同ドメインに関わる複数のメソッドを定義できる getArticle(String id)とか Data 17

Slide 18

Slide 18 text

Data ● 実際にリクエストするメソッド 18

Slide 19

Slide 19 text

Data ● Dioの依存をriverpodのProviderを使ってDI ● Dioに依存したdatasourceのインスタンスをProviderで配布 19

Slide 20

Slide 20 text

全体像 20 UI State Domain Data

Slide 21

Slide 21 text

Domain ビジネスオブジェクトを含む、アプリケーションの中核となるレイヤー メソッドは1つしか実装できない UseCaseは他のUseCaseへの参照はできない Stateが複数UseCaseを持つのはOK 21

Slide 22

Slide 22 text

Domain UseCaseはDataSourceに依存 22

Slide 23

Slide 23 text

Domain UseCaseはDataSourceに依存 DataSourceで定義したProviderを 使ってUseCaseのインスタンスを配 布する際にDIして提供する 23

Slide 24

Slide 24 text

Domain DataSourceのコールにパラメータが必要 な場合 24

Slide 25

Slide 25 text

Domain DataSourceのコールにパラメータが必要 な場合 パラメータが1つでもUseCaseParamのオ ブジェクトを作ってUseCaseに渡す 25

Slide 26

Slide 26 text

全体像 26 UI State Domain Data

Slide 27

Slide 27 text

State 1つの状態だけを持つViewModel的な存在 Recoilの思想を取り入れて、1つのStateの粒度を可能な限り小さくする 27 https://recoiljs.org/

Slide 28

Slide 28 text

State StateのProviderを作る時はStateNotifierProviderを使う 28

Slide 29

Slide 29 text

State 29 トップ画面 記事一覧画面

Slide 30

Slide 30 text

State UseCaseの依存解決にParamが必要な場合 familyを使ってProviderを作るパラメータを増やす このときParamが変更されると古いParamを持ったProviderは再利用されず溜まってい き、メモリリークの原因となるためautoDisposeもセットで使う 30

Slide 31

Slide 31 text

Selector Stateをなにかしら計算してUIに渡したいときに定義 複数のStateを参照して計算した値をSelectorで定義してUIに配布もできる 31

Slide 32

Slide 32 text

State よくあるStateの動き 32

Slide 33

Slide 33 text

State よくあるStateの動き 33 loading Request Request

Slide 34

Slide 34 text

よくあるStateの動き State 34 loading Data Data

Slide 35

Slide 35 text

State よくあるStateの動き 35 idle(loaded) Data Data Data

Slide 36

Slide 36 text

State よくあるStateの動き(異常系) 36 idle(loaded) Error Data Data

Slide 37

Slide 37 text

State これらの状態をAsycEntity、 AsyncStateNotifierで表現 37

Slide 38

Slide 38 text

全体像 38 UI State Domain Data

Slide 39

Slide 39 text

UI - Connected Screen StatefulなPage StateとStatelessなHogePageを繋ぎこむ役目 StateProviderの保持と、loadingなどの状態に よってWidgetを出し分けるため DefaultContainerでAsyncEntityの値を処理す る 39

Slide 40

Slide 40 text

UI - Connected Screen DefaultContainer Stateから渡ってきた複数のAsyncEntityの値を処理してWidgetの出し分けを担う 40 ロード中 ロード終了 エラー発生

Slide 41

Slide 41 text

UI - Stateless Screen StateをもたないWidget群 ● ListView ● TextView ● Container ● Column ● … 41

Slide 42

Slide 42 text

riverpod使用ルール 42

Slide 43

Slide 43 text

riverpod使用ルール Providerの作り方はたくさんある ● Provider ● StreamProvider ● StateProvider ● StateNotifierProvider ● FutureProvider https://riverpod.dev/docs/concepts/providers 43

Slide 44

Slide 44 text

Providerのreadの仕方もいっぱいある https://riverpod.dev/docs/concepts/reading riverpod使用ルール 44

Slide 45

Slide 45 text

riverpod使用ルール ルール①:FutureProvider / StreamProviderの代わりに StateNotifierProvider+AsyncStateNotifier 45 NG OK

Slide 46

Slide 46 text

riverpod使用ルール ルール②:StateProviderの代わりにStateNotifierProvider+StateController 46 NG OK

Slide 47

Slide 47 text

riverpod使用ルール ルール③:Provider作成時はref.readは使わないでref.watchのみで統一 47 NG OK

Slide 48

Slide 48 text

riverpod使用ルール ■ まとめ 1. FutureProvider / StreamProviderの代わりに StateNotifierProvider+AsyncStateNotifier 2. StateProviderの代わりにStateNotifierProvider+StateController ➢ プロジェクトで使うProviderをProviderとStateNotifierProviderに制限 3. Provider作成時はref.readは使わないでref.watchのみで統一 ➢ 依存しているProviderが再生成されたときに、変化した値を購読できるよ うにするため ➢ 設計の統一性、Providerの依存を見やすくする 48

Slide 49

Slide 49 text

参考リンク 49 ● https://riverpod.dev/docs/getting_started ● https://recoiljs.org/ ● https://zenn.dev/riscait/books/flutter-riverpod-practical-introduction/viewer/mig rate-to-v1

Slide 50

Slide 50 text

Thank you 50