Description
Reviving musings from #6, I'm going to post my progress on working on time travel & other devtool goodness here.
I have a working proof of concept of time travel that uses the default dispatcher and relies on store composition to keep a log of state. This is not feature-complete (only “jumping to state #N” is supported), but shows how to implement such functionality with Store composition:
export const StateKeys = {
LOG: Symbol('Log')
};
export const ActionTypes = {
JUMP_TO_STATE: Symbol('JUMP_TO_STATE')
};
export default function recorder(store) {
return function Recorder(state = {}, action) {
let { [StateKeys.LOG]: log = [], ...atom } = state;
let nextAtom;
switch (action.type) {
case ActionTypes.JUMP_TO_STATE:
const { index } = action;
nextAtom = log[index].nextAtom;
break;
default:
nextAtom = store(atom, action);
break;
}
log = [...log, {
action,
atom,
nextAtom
}];
return {
[StateKeys.LOG]: log,
...nextAtom
};
}
}
Usage:
const store = composeStores(stores);
const dispatcher = createDispatcher(recorder(store)); // wrap the store
const redux = createRedux(dispatcher);
This relies on the root atom being “normal” a JS object though. I think we'll need to store it internally as atom
field instead inside a plain JS object created by us to support such “hidden” tool state.
I'd accept a PR that hides the user store's state inside an atom
field on the Redux instance's state
object, at the same time preserving the current API and behavior exactly. Redux.getState()
should keep retuning that atom. Any other fields on the internal state
will be assumed to be only used by the devtools.