aurelia / store

Aurelia single state store based on RxJS
MIT License
103 stars 27 forks source link

StateHistory and reducers #11

Closed searus closed 6 years ago

searus commented 6 years ago

First up, I like what you've done here. I have a reasonably large aurelia application that I'm building for a client which I am looking forward to leveraging this for.

My question is about having a record of the reducer that was used to transition between states. I'm thinking that the StateHistory would need to change to something like this:


export interface StateHistoryItem<T> {
  state: T;
  reducer: ??
}
export interface StateHistory<T> {
  past: StateHistoryItem<T>[],
  present: StateHistoryItem<T>,
  future: StateHistoryItem<T>[]
}

Does this make sense, or am I missing something in my understanding?

zewa666 commented 6 years ago

What would be the use case to do so and why not keep that Info in the state itself?

searus commented 6 years ago

I'm thinking in terms of time travel debugging. It's one thing know what the state is at any given time in an application, but knowing what reducers/actions were executed to get to that state could be useful.

It's also what you get in the Redux dev tools which is what made me think of it here.

Just wanted to raise it as a discussion point to see if you had considered it or if it was on the roadmap. There are certainly workarounds possible by recording the reducer/action in the state itself, maybe by using higher order function.

zewa666 commented 6 years ago

Definitely thanks for starting the discussion, its always helpful to get other ideas and viewpoints.

So as for the DevTools integration, this is already happening, which is also the reason for asking for a name when registering Actions. What you're after sounds more like the means how to reach a certain state in time. I'm essentially using a memento pattern for implementing the undo feature, much like the general behaviour is for most Redux based implementations.

There would be an alternative approach, where you'd not store the states over time, but the series of actions that lead to certain states. The problem here though is that sadly not every action can be easily negated. Think of a server API not providing the counterpart to your add method. So generally that implementation tends to become quite hard for edge cases, and those are always present in any app more than a trivial todo example.

Yes using a HoF like dispatchify would allow to wrap all your actions to add the knowhow of how to store itselfs name into the debug prop of the state.

One reason I'm not sure whether this should be baked right into the Undo feature and its Interface is that it is already more complex compared to the undo-less version. So adding even further needs for a three levels deep history state representation feels like a lot of weight just for the sake of debug-ability, even though this could be achieved by putting your info into the state itself.

<div>${state.name}</div>

vs.

<div>${state.present.name}</div>

vs.

<div>${state.present.state.name}</div>

The more features we cram into undo/redo or any other behaviour the more boilerplate everybody needs to handle, as such the benefit should be definitely given for a large user base.

How do you think about it?

searus commented 6 years ago

Thanks for the detailed reply!

My reasononing for catpuring the actions/reducers was just to provide useful debugging, rather than as a way to rebuild state (e.g. Event Sourcing). As you rightly say, once you involve server side persistence, that becomes a nightmare. I'm looking forward to seeing your work on the DevTools.

Also, I agree that it is a good idea to try and avoid overcomplicating the API. I briefly looked at the possibility of something like this:

    store.state.subscribe((state: Store<IStore>, history: StateHistory<IStore>) => {
      ...
    });

But, I now I see the subscribe method is part of RxJS... something I haven't got my head around yet :)

Thanks again for taking the time to explain everything. I can't wait to make use of this in my apps!

zewa666 commented 6 years ago

As for the DevTools, just install the Redux DevTools, visit your running app, and you should see all the state propagated and navigatable. Thanks again for the discussion