Skip to content

Adding ReduxStoreWithHistory to allow undo/redo operations.#9

Merged
Odonno merged 3 commits into
Odonno:masterfrom
surgeforward:feature/history
Mar 26, 2018
Merged

Adding ReduxStoreWithHistory to allow undo/redo operations.#9
Odonno merged 3 commits into
Odonno:masterfrom
surgeforward:feature/history

Conversation

@mhusainisurge
Copy link
Copy Markdown
Contributor

We can iterate over the design a bit, but this will accomplish what #1 asks for.

Comment thread ReduxSimple/ReduxStore.cs Outdated
{
State = state;

if (action != null)
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is breaking change compared to the last version. Let's create an issue to discuss how to handle null action and remove the check on this PR.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I created #10 to discuss it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The original intent of this check was to allow the overloaded method to pass a null in here, but you have a good point about breaking change. I'll revisit this.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well. Let's see if you still need to do it on your next iteration.

Comment thread ReduxSimple/ReduxStoreWithHistory.cs Outdated
public abstract class ReduxStoreWithHistory<TState> : ReduxStore<TState>
where TState : class, new()
{
private readonly Stack<TState> _previousStates = new Stack<TState>();
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be better to stack Action instead of State? If you have an initial state + the list of actions, you can recreate any State at any time.

And the main advantage is that an Action is generally lighter than a State.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, I will refactor this.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was thinking about it for the last 10 minutes. I think the best solution is still to only save a list of Action.

But if you have executed a lot of actions and you want to go back in history, you will call the Reduce function too much. A smart way to handle that is to store a State at regular interval (of actions) in an attempt to optimize the move in history. We can plan that for a later version since it is simply an optimization and not a full feature.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm thinking if we saved the action and the previous state at each step, then we can always recreate any state. Will try it out.

Comment thread ReduxSimple/ReduxStoreWithHistory.cs Outdated
where TState : class, new()
{
private readonly Stack<TState> _previousStates = new Stack<TState>();
private readonly Stack<TState> _nextStates = new Stack<TState>();
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same. But we can save both forward Actions and UndoneActions, or a better name if you have.

Comment thread ReduxSimple/ReduxStoreWithHistory.cs Outdated

_nextStates.Push(State);

GoToState(_previousStates.Pop());
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to know what devs think will happen when using the Undo method.

Should we trigger a new OnNext event for the State and the Action? Does it make it sense because to me it will like we continue the flow of actions forward and not going backward? Should we introduce new Subject<Action> per Undo call so devs will handle the change by themselves?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking that triggering a new event for Action would be kind of awkward because we're not technically performing the action again when we undo. Your idea for having a separate Subject<Action> for Undo calls makes sense though.

Comment thread ReduxSimple/ReduxStore.cs Outdated
return _actionSubject.OfType<T>().AsObservable();
}

private void GoToState(TState state, object action)
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure we need to extract the method. Based on my comments, the code should normally go back to Dispatch method.

@Odonno
Copy link
Copy Markdown
Owner

Odonno commented Mar 25, 2018

https://media.giphy.com/media/TBvEYkHRUKBWM/giphy.gif

Wow. Thank you for taking the lead on what I can call the largest PR of the history of this project. :)

Of course, there will be iteration on it but for now, it's a great start. Already made some comments we can discuss.

@Odonno Odonno added the feature New feature or request label Mar 25, 2018
@mhusainisurge
Copy link
Copy Markdown
Contributor Author

Made some changes based on your comments. I had to keep a version of the GoToStep method since the base class is not capable of dealing with an undo operation, which is not a traditional reduce operation.

Another difference is that previously _actionSubject was emitting before _stateSubject and now that order is reversed. I wasn't sure if that order was significant or not, but if it is, I can try to enforce it as well (a little bit more work than what I have now, but nothing that can't be managed).

Copy link
Copy Markdown
Owner

@Odonno Odonno left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks close to perfection.

Comment thread ReduxSimple/ReduxStore.cs Outdated
return _actionSubject.OfType<T>().AsObservable();
}

protected void GoToState(TState state)
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose we can now rename the method UpdateState.

Comment thread ReduxSimple/ReduxStoreWithHistory.cs Outdated
private readonly Stack<object> _futureActions = new Stack<object>();

public bool CanUndo => _pastMementos.Count != 0;

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can remove this line return.

Comment thread ReduxSimple/ReduxStoreWithHistory.cs Outdated
private class ReduxStoreMemento
{
public TState State { get; }

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can remove this line return.

Comment thread ReduxSimple/ReduxStore.cs Outdated
State = Reduce(State, action);

GoToState(Reduce(State, action));
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can remove this line return.

@Odonno
Copy link
Copy Markdown
Owner

Odonno commented Mar 26, 2018

About the order of Subject publication, I don't think the order matters. What is important is that they should be published at the same time, one after another, and that is still the case.

Copy link
Copy Markdown
Owner

@Odonno Odonno left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's huge. Nice job.

@Odonno Odonno merged commit 1d658a8 into Odonno:master Mar 26, 2018
@Odonno Odonno added this to the 1.1 milestone Mar 26, 2018
@mhusainisurge mhusainisurge deleted the feature/history branch March 26, 2018 15:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants