top of page

[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/Dart】TextFieldで文字列をフォーマットする

やりたいこと TextFieldで入力フォームを作りたい。 例えば入力内容が金額の場合、3桁区切りで頭に¥を付けた表記にしたい。 ただしユーザにこれらを入力させるのではなく、ユーザはあくまで数字を入力するだけで、アプリ側で自動でフォーマットしたい。 方法 TextInputFormatterを継承し、所望のフォーマット処理を追加することで実現可能。 例えばこの記事などを参照。 以下は個人的に躓いた

【Flutter/Dart】iosシミュレータ起動後にデバイスに保存した画像が見つからない

現象 やってること iosシミュレータで画像をデバイスのローカルに保存 保存したパスをデータベースに保存 アプリ立ち上げ時にデータベースから画像パスを取得し、そのパスの画像を画面上に表示 起きている現象 iosシミュレータを再起動した場合、上記3で「ファイルパスが見つからない」というエラーが出る 原因 保存時のディレクトリを getApplicationDocumentsDirectory() に

【Flutter/dart】late変数が初期化されたかのチェック

やりたいこと 初期値さえ決まればあとは不変な変数がある ただし、コンストラクタ起動時にはまだ決定できない このような変数について late finalで変数を定義 (何らかのタイミングで)初期化されたかどうかをチェックし、されていなければ値を入れる(チェックしないとfinalに値を代入したエラーになるので) この場合、「初期化されたかどうか」はどのようにチェックしたらいいのか分からなかった nul

あなたの買い物をサポートする
アプリ Shop Plan

iphone6.5p2.png

​いつ何を買うかの計画を立てられるアプリです。

google-play-badge.png
Download_on_the_App_Store_Badge_JP_RGB_blk_100317.png

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

納品:iPhone6.5①.png

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

google-play-badge.png
Download_on_the_App_Store_Badge_JP_RGB_blk_100317.png

「後で読む」を忘れないアプリ ArticleReminder

気になった​Webサイトを登録し、指定時刻にリマインダを送れるアプリです

google-play-badge.png
Download_on_the_App_Store_Badge_JP_RGB_blk_100317.png
bottom of page