Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions src/Redux.Tests/Reactive/StoreExtensionsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,19 @@ public void ObserveState_should_push_store_states()

CollectionAssert.AreEqual(new[] { 1, 2 }, spyListener.Values);
}

[Test]
public void ObserveActions_should_push_actions()
{
var sut = new Store<int>(Reducers.Replace, 0);
object receivedAction = null;

sut.ObserveActions().Subscribe(action => receivedAction = action);

var dispatchedAction = new object();
sut.Dispatch(dispatchedAction);

Assert.AreSame(receivedAction, dispatchedAction);
}
}
}
26 changes: 26 additions & 0 deletions src/Redux.Tests/StoreTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -119,5 +119,31 @@ await Task.WhenAll(Enumerable.Range(0, 1000)

Assert.AreEqual(1000, sut.GetState());
}

[Test]
public void Should_push_action_on_dispatch_to_reducer()
{
var sut = new Store<int>((state, action) => state + 1, 0);
object pushedAction = null;
sut.ActionDispatched += action => pushedAction = action;
var dispatchedAction = new object();

sut.Dispatch(dispatchedAction);

Assert.AreSame(dispatchedAction, pushedAction);
}

[Test]
public void Should_not_push_action_when_middleware_stops()
{
Middleware<int> stoppingMiddleware = store => next => action => null;
var sut = new Store<int>((state, action) => state + 1, 0, stoppingMiddleware);
var actionWasPushed = false;
sut.ActionDispatched += action => actionWasPushed = true;

sut.Dispatch(new object());

Assert.False(actionWasPushed);
}
}
}
14 changes: 13 additions & 1 deletion src/Redux/IStore.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System;

namespace Redux
namespace Redux
{
/// <summary>
/// Represents a store that encapsulates a state tree and is used to dispatch actions to update the
Expand Down Expand Up @@ -31,6 +31,18 @@ public interface IStore<TState>
/// </returns>
TState GetState();

/// <summary>
/// Occurs after an action has been dispatched to the reducer.
/// </summary>
event Action StateChanged;

/// <summary>
/// Occurs after an action has been dispatched to the reducer. The action is passed to the event
/// handlers.
/// </summary>
/// <remarks>
/// This event is primarily intended for extending the store. For subscribing to state changes, use <see cref="StateChanged" />.
/// </remarks>
event Action<object> ActionDispatched;
}
}
8 changes: 8 additions & 0 deletions src/Redux/Reactive/StoreExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,13 @@ public static IObservable<T> ObserveState<T>(this IStore<T> store)
h => store.StateChanged -= h)
.Select(_ => store.GetState());
}

public static IObservable<object> ObserveActions<T>(this IStore<T> store)
{
return Observable
.FromEvent<object>(
h => store.ActionDispatched += h,
h => store.ActionDispatched -= h);
}
}
}
4 changes: 4 additions & 0 deletions src/Redux/Store.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ public event Action StateChanged
}
}

public event Action<object> ActionDispatched;


public object Dispatch(object action)
{
return _dispatcher(action);
Expand Down Expand Up @@ -60,6 +63,7 @@ private object InnerDispatch(object action)
}

_stateChanged?.Invoke();
ActionDispatched?.Invoke(action);

return action;
}
Expand Down