[Flutter/dart] Redux Storeの状態を保存する/redux_persistの使い方


概要


ユーザの設定したデータをアプリ終了後も保持したい場合が多々あります。状態管理にreduxを用いている場合はredux_persistというライブラリを使えば簡単にデータを永続化できます。



方法


※flutter_reduxはすでに導入されているという前提でお話します。


公式サイト


導入


まずはpubsec.yamlに以下を追記します。

dependencies:
    redux_persist: ^0.8.4

main.dartの冒頭でライブラリをimportします。

(基本的にmain.dartで使用するかと思いますが、違う場合は適宜読み替えてください)

import 'package:redux_persist/redux_persist.dart';


準備


管理する状態をAppStateとします。AppStateに必要な処理を追加していきます。


まだデータが無い場合の初期化処理が必要です。

class AppState{

  String item;
  int number;
  
  AppState({@required this.items, this.partners});
  
  //初期化処理
  AppState.InitState() {
    item="";
    number=0;
  }
}

状態を保存する際にはデータをjson形式に変換します。jsonへの変換とjsonからの読み出し処理を追加します。

//jsonへ変換
Map toJson()=>{
  'item': item,
  'number': number,
};

//jsonから読み出し
static AppState fromJson(dynamic json){
  AppState state=AppState(
    item: json['item'],
    number=json['number']
  );
  
  return state;
}


保存処理


ここからが本題です。mainのrunApp()の前に以下の処理を追加してください。

void main() async{

//ローカルディレクトリのパスを取得
  String _storage_path=await getLocalDir();
  final persistor = Persistor<AppState>(
    storage: FileStorage(File("${_storage_path}/state.json")),
    serializer: JsonSerializer<AppState>(AppState.fromJson),
  );  //※1 perstorを作成

  AppState initialState;
  try{
    initialState=await persistor.load();
  }
  catch(e){
    initialState=null;
  }  //※2 persistorからデータを読み出し

  final Store<AppState> store=Store<AppState>(
    appStateReducer,  //※自作のreducer
    initialState: initialState?? AppState.InitState(),
    middleware: [AppStateMiddleWare, persistor.createMiddleware()]
  ); //※3 storeの初期化
  
  runApp(MyApp(store: store,));
}

まずpersistorインスタンスを作成します。(※1)

storage:にはデータの保存先を指定します。ここではローカルファイルへの保存を用いますが、他にもwebなどにも保存できるみたいです。ローカルディレクトリの取得には以下のメソッドを用いています。

static Future<String> getLocalDir() async {
  final directory = await getApplicationDocumentsDirectory();
  return directory.path;
}

serializer:にはデータのシリアライザを指定します。ここではJsonSerializerを用い、decoderに先に作成したfromJsonメソッドを指定します。


次に、persistorからデータを読み出します(※2)。データがまだ保存されていない場合などはfromJsonがnullを返すため例外処理を入れます。(後で初期化処理を入れていますが、ここのcatch文で入れてもいいかも)


最後にStoreを初期化します(※3)。

initState:に先ほどpersistorから読み出したstateを入れ、nullが返ってきている場合はstateを初期化します。

データを保存する処理はredux_persistorで用意されているmiddlewareで行われます。persistor.createMiddleware()で生成されるmiddlewareをmiddleware:に指定します。



middlewareについて


・データ保存のタイミングは?


createMiddleware()のソースは以下のようになっています。

Middleware<T> createMiddleware() {
  Timer _saveTimer;

  return (Store<T> store, dynamic action, NextDispatcher next) {
    next(action);

    if (shouldSave != null && shouldSave(store, action) != true) {
      return;
    }

    // Save
    try {
      if (throttleDuration != null) {
        // Only create a new timer if the last one hasn't been run.
        if (_saveTimer?.isActive != true) {
          _saveTimer = Timer(throttleDuration, () => save(store.state));
        }
      } else {
        save(store.state);
      }
    } catch (_) {}
  };
}

next(action)の後にsave()処理があるので、action(データの変更など)の後にデータが保存されます(当たり前)。


・自作のmiddlewareを使いたい


データの保存以外にもmiddlewareにやらせたいことはありますよね。そのような処理を記述した自作のmiddlewareも使用したい場合は、それらをListにまとめてmiddleware:に渡せば大丈夫です。

Listの先頭から順にmiddlewareの処理が実行され、next()で次のmiddlewareが実行されます。最後のmiddlewareのnextがactionになります。処理の順番が重要な場合はListの順番とnextの位置に注意してください。



最後に


実は最初redux_persistorの存在を知らずにshared_preferenceにデータを保存していましたが、redux_persistを使えばかなり簡単にデータを保存することができます。調べることって大切ですね、、、


最新記事

すべて表示

現象 flutter_local_notificationを使って通知を作成。通知タップ時の動作も登録。 通知が来た時にアプリが立ち上がっている(foregroundでもbackgroundでも)と、期待通りの動作となる。 しかし、通知が来た時にアプリが終了していると、通知をタップしても登録した動作とならない。 原因と解決策 アプリが終了すると登録した動作は消えてしまうらしい(参考)。 Note:

概要 Firebase Messagingでメッセージを送信し、通知がタップされたら何らかの動作を実行する(例:特定のページに移動する)という場合は多いかと思います。 通知タップ時にアプリがforeground状態(つまりアプリを開いている)ならば簡単なのですが、アプリがbackground状態にある場合は少し工夫が必要です。 方法 FirebaseMessaging.onBackgroundMe

現象 FirebaseMessaging.onBackgroundMessage()でタイトルのエラーが発生。 原因と解決策 上記メソッドの引数に渡すデリゲートはトップレベル関数でなければならない。自分の場合はインスタンスメソッドを渡していたのでエラーとなった。 渡すメソッドをトップレベル関数にするとエラーは解消した。 @main.dart void main() async{ //略 F

靴を大切にしよう!靴管理アプリ SHOES_KEEP

納品:iPhone6.5①.png

靴の履いた回数、お手入れ回数を管理するアプリです。

google-play-badge.png
Download_on_the_App_Store_Badge_JP_RGB_blk_100317.png

テーマ日記:テーマを決めてジャンルごとに記録

訂正①2040×1152.jpg

ジャンルごとにテーマ、サブテーマをつけて投稿、記録できる日記アプリです。

google-play-badge.png