FlutterにReduxアーキテクチャを実装させる

  • このエントリーをはてなブックマークに追加

Flutterでアプリ開発を深く進めていたら、Widget間のデータのやり取りや状態(State)の管理、UIの制御が複雑になり、シンプルなアプリの域を超えてしまうとデータ管理が難しいなと思い、「状態管理」をするためにFlutterにソフトウェアアーキテクチャを導入することにしました。

 

今回は、Web開発で以前に利用した事があり、Flutterでも利用可能な「Redux」アーキテクチャパターンを採用してみることにしました。

この記事では、FlutterでどのようにReduxアーキテクチャパターンを導入・利用していくのかについて紹介していきます。

Reduxとは?

Reduxアーキテクチャは、元々あるFluxというアーキテクチャパターンを拡張(発展)して作られたものです。

Reduxについては、Flutter内にどのように実装するかに焦点を当てて紹介しますので、

ここではざっくりしか説明しません。

 

Reduxの特徴は、「Store」と呼ばれるオブジェクトの中で、アプリケーション全ての状態を保管して、

呼び出し、更新の全てをStoreを通して行います。

商品在庫を保管、加工できる倉庫のようですね。

そして、この「Store」はアプリケーションに1つ限り、唯一の存在でなければいけないという規約があります。

1つの場所で一元管理する事で、データ管理の複雑化を防ぎます。

 

状態変化の流れは以下の通りです。

■画面から値の更新

「View」→「Action」①→「Reducer」②→「Store」

■更新を画面に伝える

「View」←③「Store」

①「View(画面)」から何らかの「Action」を「Reducer」へ渡す。

②「Reducer」で「View」から渡ってきた「Action」を解析して、「Store」内で管理している状態データを更新する。

③「Store」から、更新された状態データを「View」へ受け渡します。

 

↓Reduxについてはこちらの記事が参考になったので、一度ご覧になってみてください。

参考:FlutterでReduxに入門する

 

FlutterプロジェクトにReduxを実装する

ここから先はこちらの記事を参考にさせていただきました。

参考:Flutterのアプリ設計(Redux)

 

①Reduxライブラリを導入する

pubspec.yamlにflutter_reduxを導入します。

 

②Storeに取り入れるState(状態管理データ)クラスを作成する

Storeに管理させるデータを「State」クラスを作成して管理します。

例えば、選択された値、ON/OFF、カウンターなどをStateクラスの中にメンバ変数として宣言します。

例として、Navigationの選択されたindex値を保持したりするNavigationに関するStateを管理するNavigationStateクラスを作成しました。

 

classの上についているアノテーション「@immutable」は「不変」を意味し、クラス内のメンバ変数が変更不可であることを示す事ができます。

これはRedux3原則の一つの「stateは読み取り専用」を実現するためです。

メンバ変数は全てfinalで宣言し、「Reducer」で更新させる為にコンストラクタでメンバ変数を初期化しています。

 

しかし、このようなStateクラスをたくさん用意した場合に、後述するStoreの初期化時に複数のStateクラスを一気に初期化して保持できるようひと工夫する必要があります。

RootStateというクラスを作成し、全てのStateクラスをメンバ変数として保持します。

そして、コンストラクタで全てのStateクラスを初期化させます。

 

③状態をどのように変更するかの指標となるActionクラスを作る

次に、「Action」クラスを作ります。

Stateクラスの更新方法は、「Reducer」が画面から渡ってきた「Action」情報を元に判断します。

その為、単に「class ChangeNavigationIndexAction{}」のような空っぽのクラスでOKです。

ただし、「画面から指定した値にデータを変更したい」などの場合はパラメータを受け取る必要があるので、

以下のように宣言します。

Actionクラスも必要な更新方法の数だけ複数作ります。

 

④Actionを受け取ってStateクラスの情報を更新するReducerを作る

上でも言った通り、Reducerで受け取ったActionを判別して適切にStateクラスを更新します。

Stateクラスごとに Reducerを作って管理します。

Stateクラス型のReducerは関数で、引数に現在のState、Action情報を渡します。

IF文を利用して、渡ってきたActionを判定します。

引数で渡ってきたactionはActionクラスにパラメータを設定していた場合、引き出す事ができます。

最後にStateクラスを新しい値で作り直します。

こちらもRootReducerを作って、Stateクラスの初期化を管理します。

 

 

⑤はじめに呼ばれるStatelessWidget内でStoreをインスタンス化

下準備が整ったので、Storeを構築します。

StatelessWidget内で、Storeをインスタンス化してメンバ変数として保持します。

 

⑥StoreConnectorを使ってWidgetの状態を更新する

以下はNavigationの切り替えによって画面の表示内容が切り替わるWidgetの例です。

本来このような動的な動きをさせるにはStatefulWidgetを使用してStateを更新させる必要がありますが、

Reduxで状態管理しているので、StatelessWidgetでも動的更新が可能です。

Stateクラスの状態を更新するには「store.dispatch(ChangeNaviIndexAction(index: index));」のようにActionクラスとパラメータ(有れば)を指定することでReducerが検知し、Stateを変更させる事ができる仕組みです。

 

Widgetの動的に更新をかけたい箇所は「StoreConnector」でラップします。

 

実際に動かしてみると、StatelessWidgetでも画面が更新されるのが分かります。

 

まとめ

かなり複雑で、他の文献をあさったりと、理解に苦しみました…。

実際に構築してみると、それぞれのWidget間でデータの受け渡しが煩わしくなくシンプルに済むので、

複雑になりそうなアプリの構築には真価を発揮するのではないかと思います。

  • このエントリーをはてなブックマークに追加

SNSでもご購読できます。

コメントを残す

*