redux_undo.dart
This package will make your redux store undoable.
Things to come in the future
- Support for making only a slice of the state undoable
- more examples and documentation
Installation
define the dependency in your pubspec.yaml file:
dependencies: redux_undo: ^1.0.0+1
update your applications packages by running
or when using flutter as a framework
import the package to use in the file you are setting up redux:
import 'package:redux_undo/redux_undo.dart';
Structure
redux_undo will slightly modify your state by adding a new properties-layer at the root of the store. The final structure will look like this:
/// when accessed directly from the store, store.state will have this structure UndoableHistory<S> state = { past: <S>[], present: null, // <-- the current state of the app future: <S>[], latestUnfiltered: null // <-- basically equals present, to store a mutual state before storing it into past or future };
Usage
Because it modifies the initial state you need to initiate redux_undo when initiating the redux store.
This is done by calling 2 separate functions:
/// to wrap the root reducer Reducer<UndoableState<S>> createUndoableReducer<S>(Reducer<S> reducer, { UndoableConfig config }); /// to wrap the Root state of your app. UndoableState<S> createUndoableState<S>(S initialState, bool ignoreInitialState);
Here is an example of how this can be done in a flutter app:
import 'package:flutter/material.dart'; import 'package:flutter_redux/flutter_redux.dart'; import 'package:redux/redux.dart'; import 'package:redux_undo/redux_undo.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { final Store<UndoableState<RootState>> store = Store<UndoableState<RootState>>( createUndoableReducer<RootState>(rootReducer), initialState: createUndoableState(RootState.initial(), false), ); @override Widget build(BuildContext context) { return StoreProvider<UndoableState<RootState>>( store: store, child: MaterialApp( title: 'Redux Undo Demo', home: const MyHomePage(), ), ); } }
Actions
redux_undo provides 4 basic actions
-
UndoableUndoAction- Standard-Action for undoUsage:
store.dispatch(UndoableUndoAction()) -
UndoableRedoAction- Standard-Action for redoUsage:
store.dispatch(UndoableRedoAction()) -
UndoableJumpAction- Standard-Action for jump (to past or to future)Usage:
store.dispatch(UndoableJumpAction(index: -2))// <- jumps 2 steps to the past (same as dispatchingUndoableUndoActiontwice)Usage:
store.dispatch(UndoableJumpAction(index: 0))// <- does nothing, since it just returns the currentUndoableStateUsage:
store.dispatch(UndoableJumpAction(index: 2))// <- jumps 2 steps to the future (same as dispatchingUndoableRedoActiontwice) -
UndoableClearHistoryAction- Standard-Action for clearing the history
Options
It is possible to provide a configuration object to the UndoableState instantiation like this:
final UndoableConfig config = UndoableConfig( limit: 100, blackList: <Type>[ BlacklistedAction, ], whiteList: <Type>[ WhitelistedAction, ], );
Then pass it to the createUndoableReducer function like this:
final Store<UndoableState<RootState>> store = Store<UndoableState<RootState>>( createUndoableReducer<RootState>(rootReducer, config: config), initialState: createUndoableState(RootState.initial(), false), );
These are the options the UndoableConfig class provides:
- int limit: limits the length of the
UndoableState.pastList and with this ultimately the length ofUndoableState.futureas well- default value => 10
- List whiteList: actions in this list need to be extended from one of the provided
redux_undoactions and will fire the originalrootReducerafter performing the action they extended from without updatingUndoableState.pastorUndoableState.future