[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を使えばかなり簡単にデータを保存することができます。調べることって大切ですね、、、
最新記事
すべて表示やりたいこと TextFieldで入力フォームを作りたい。 例えば入力内容が金額の場合、3桁区切りで頭に¥を付けた表記にしたい。 ただしユーザにこれらを入力させるのではなく、ユーザはあくまで数字を入力するだけで、アプリ側で自動でフォーマットしたい。 方法...
現象 やってること iosシミュレータで画像をデバイスのローカルに保存 保存したパスをデータベースに保存 アプリ立ち上げ時にデータベースから画像パスを取得し、そのパスの画像を画面上に表示 起きている現象 iosシミュレータを再起動した場合、上記3で「ファイルパスが見つからな...
やりたいこと 初期値さえ決まればあとは不変な変数がある ただし、コンストラクタ起動時にはまだ決定できない このような変数について late finalで変数を定義 (何らかのタイミングで)初期化されたかどうかをチェックし、されていなければ値を入れる(チェックしないとfina...
Comments