在移动端的开发中我们如何获取用户是否登录呢,一般我们最常用的做法是在用户登录后将获取的token存在本地然后在用户下次登录的时候我们从本地读取这个token如果有那么我们判断用户之前登录过,如果没有我们就知道用户没有登录.但是在接触了redux以后发现redux有自己的数据持久化Redux Persist.那今天简单研究一下我们如何使用Redux Persist进行状态的管理
首先我们就是想储存一些我们已经获取的数据这个时候redux_persist_flutter给我们提供了一个关键的类Persistor,那我们点进去看看这个Persistor到底是个什么
class Persistor<T> {
/// Storage engine to save/load from/to.
final StorageEngine storage;
/// Transformations on state to be applied on save/load.
final Transforms<T> transforms;
/// Transformations on raw data to be applied on save/load.
final RawTransforms rawTransforms;
/// State serialized used to serialize the state to/from bytes.
final StateSerializer<T> serializer;
/// Debug mode (prints debug information).
bool debug;
/// Duration for which to throttle saving. Disable by setting to null.
/// It is recommended to set a duration of a few (2-5) seconds to reduce
/// storage calls, while preventing data loss.
/// A duration of zero (default) will try to save on next available cycle
Duration throttleDuration;
/// Synchronization lock for saving
final _saveLock = Lock();
/// Function that if not null, returns if an action should trigger a save.
final bool Function(Store<T> store, dynamic action) shouldSave;
Persistor({
@required this.storage,
@required this.serializer,
this.transforms,
this.rawTransforms,
this.debug = false,
this.throttleDuration = Duration.zero,
this.shouldSave,
});
/// Middleware used for Redux which saves on each action.
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 (_) {}
};
}
/// Load state from storage
Future<T> load() async {
try {
_printDebug('Starting load...');
_printDebug('Loading from storage');
// Load from storage
Uint8List data;
try {
data = await storage.load();
} catch (error) {
throw StorageException('On load: ${error.toString()}');
}
_printDebug('Running load raw transformations');
try {
// Run all raw load transforms
rawTransforms?.onLoad?.forEach((transform) {
data = transform(data);
});
} catch (error) {
throw TransformationException(
'On load raw transformation: ${error.toString()}',
);
}
_printDebug('Deserializing');
T state;
try {
state = serializer.decode(data);
} catch (error) {
throw SerializationException('On load: ${error.toString()}');
}
_printDebug('Running load transformations');
try {
// Run all load transforms
transforms?.onLoad?.forEach((transform) {
state = transform(state);
});
} catch (error) {
throw TransformationException(
'On load transformation: ${error.toString()}',
);
}
_printDebug('Done loading!');
return state;
} catch (error) {
_printDebug('Error while loading: ${error.toString()}');
rethrow;
}
}
/// Save state to storage.
Future<void> save(T state) async {
try {
_printDebug('Starting save...');
_printDebug('Running save transformations');
// Run all save transforms
try {
transforms?.onSave?.forEach((transform) {
state = transform(state);
});
} catch (error) {
throw TransformationException(
"On save transformation: ${error.toString()}",
);
}
_printDebug('Serializing');
var data = serializer.encode(state);
_printDebug('Running save raw transformations');
try {
// Run all raw save transforms
rawTransforms?.onSave?.forEach((transform) {
data = transform(data);
});
} catch (error) {
throw TransformationException(
'On save raw transformation: ${error.toString()}');
}
_printDebug('Saving to storage');
// Save to storage
try {
// Use lock to prevent writing twice at the same time
await _saveLock.synchronized(() async => await storage.save(data));
} catch (error) {
throw StorageException('On save: ${error.toString()}');
}
_printDebug('Done saving!');
} catch (error) {
_printDebug('Error while saving: ${error.toString()}');
rethrow;
}
}
void _printDebug(Object object) {
if (debug) {
print('Persistor debug: $object');
}
}
}
我们看几个重要的属性一个是storage
final persistor = Persistor<AppState>(
storage: FlutterStorage(),
serializer: JsonSerializer<AppState>(AppState.fromJson),
);
官方实例中给出了一个FlutterStorage,继续点击看一下这是个什么东西
class FlutterStorage implements StorageEngine {
StorageEngine _locationEngine;
FlutterStorage({
String key = "app",
FlutterSaveLocation location = FlutterSaveLocation.documentFile,
}) {
switch (location) {
case FlutterSaveLocation.documentFile:
_locationEngine = DocumentFileEngine(key);
break;
case FlutterSaveLocation.sharedPreferences:
_locationEngine = SharedPreferencesEngine(key);
break;
default:
throw StorageException("No Flutter storage location");
}
}
看到了其实就是让我们方便设置保存的位置,默认是FlutterSaveLocation.documentFile我们也可以设置成 FlutterSaveLocation.sharedPreferences
好看第二个serializer这里就不在粘贴源码了,有兴趣的朋友可以点进去看一下就是我们储存数据的格式我们可以使用JsonSerializer这个时候我们要在状态类里提供两个方法吧我们想要保存的数据json化
class CountState{
int _count;
get count => _count;
CountState(this._count);
CountState.initState() : _count = 0;
static CountState fromJson(dynamic json) => json != null ? CountState(json['count'] as int) : CountState(0);
dynamic toJson() => {'count': _count};
}
然后我们提供一个方法用他来保存状态
Future<Store<CountState>> InitializeStore() async {
final persistor = Persistor<CountState>(
throttleDuration: Duration(seconds: 5),
//debug: true,
storage: FlutterStorage(),
serializer:
JsonSerializer<CountState>(CountState.fromJson), // Or use other serializers
);
// 从 persistor 中加载上一次存储的状态
final initialState = await persistor.load();
final store = Store<CountState>(
reducer,
initialState: initialState ?? CountState(0),
middleware: [persistor.createMiddleware()]
);
return store;
}
然后我们在runApp的头上调用我们定义的方法
Store< CountState > store = await InitializeStore();
这样就可以保存我们的状态了
写在最后
因为是移动端出身,很多理解不是很到位,欢迎指正.