public void Delays_Unsubscribe_Unitl_The_End_Of_Current_Dispatch() { var store = Redux.CreateStore(Helpers.TodosReducer, null); var unsubscribeHandles = new List <Action>(); Action doUnsubscribeAll = () => { foreach (var unsubscribeHandle in unsubscribeHandles) { unsubscribeHandle(); } }; var listener1 = new Mock <Action>(); var listener2 = new Mock <Action>(); var listener3 = new Mock <Action>(); unsubscribeHandles.Add(store.Subscribe(() => listener1.Object())); unsubscribeHandles.Add(store.Subscribe(() => { listener2.Object(); doUnsubscribeAll(); })); unsubscribeHandles.Add(store.Subscribe(() => listener3.Object())); store.Dispatch(new Helpers.UnknownAction()); listener1.Verify(x => x(), Times.Exactly(1)); listener2.Verify(x => x(), Times.Exactly(1)); listener3.Verify(x => x(), Times.Exactly(1)); store.Dispatch(new Helpers.UnknownAction()); listener1.Verify(x => x(), Times.Exactly(1)); listener2.Verify(x => x(), Times.Exactly(1)); listener3.Verify(x => x(), Times.Exactly(1)); }
public void Applies_The_Reducer_To_Previous_State() { var store = Redux.CreateStore(Helpers.TodosReducer, null); Assert.Equal(new Helpers.Todo[] { }, store.GetState()); store.Dispatch(new Helpers.UnknownAction()); Assert.Equal(new Helpers.Todo[] { }, store.GetState()); store.Dispatch(new Helpers.AddTodoAction("Hello")); Assert.Equal(new[] { new Helpers.Todo { Id = 1, Message = "Hello" } }, store.GetState()); store.Dispatch(new Helpers.AddTodoAction("World")); Assert.Equal(new[] { new Helpers.Todo { Id = 1, Message = "Hello" }, new Helpers.Todo { Id = 2, Message = "World" } }, store.GetState()); }
public static void Main() { var initialState = new TodoAppState { DescriptionInput = "", Visibility = TodoVisibility.All, Todos = new Todo[] { new Todo { Id = 0, Description = "Learn React + Redux in C#", IsCompleted = true }, new Todo { Id = 1, Description = "Build an awesome app with them", IsCompleted = false } } }; var store = Redux.CreateStore(Todos.Reducer(initialState)); React.Render(Components.TodoItemList(store), Document.GetElementById("root")); }
public void Recovers_From_Error_Within_Reducer() { var store = Redux.CreateStore(Helpers.ThrowErrorReducer, 0); Assert.Throws <Exception>(() => store.Dispatch(new Helpers.ErrorAction())); store.Dispatch(new Helpers.UnknownAction()); }
// This method gets called by the runtime. Use this method to add services to the container. // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 public void ConfigureServices(IServiceCollection services) { services.AddRazorPages(); services.AddServerSideBlazor(); services.AddSingleton <WeatherForecastService>(); services.AddStore <CounterState, IAction>("Counter 1").AddStore <CounterState2, IAction>("Counter 2"); services.AddStorage(); services.AddScoped <IRedux <CounterState, IAction>, Redux <CounterState, IAction> >(services => { var store = services.GetRequiredService <IStore <CounterState, IAction> >(); var storage = services.GetRequiredService <LocalStorage>(); //var js = services.GetRequiredService<IJSRuntime>(); var logger = services.GetRequiredService <ILogger <Redux <CounterState, IAction> > >(); var redux = new Redux <CounterState, IAction>(store, storage, logger, "Counter 1"); return(redux); }); services.AddScoped <IRedux <CounterState2, IAction>, Redux <CounterState2, IAction> >(services => { var store = services.GetRequiredService <IStore <CounterState2, IAction> >(); var storage = services.GetRequiredService <LocalStorage>(); //var js = services.GetRequiredService<IJSRuntime>(); var logger = services.GetRequiredService <ILogger <Redux <CounterState2, IAction> > >(); var redux = new Redux <CounterState2, IAction>(store, storage, logger, "Counter 2"); return(redux); }); }
public async void Passes_Recursive_Dispatches_Through_The_Middleware_Chain() { var timesCalled = 0; Action stub = () => timesCalled++; var store = Redux.ApplyMiddleware(TestRecursive <Helpers.Todo[]>(stub), Helpers.Thunk)(Redux.CreateStore)(Helpers.TodosReducer, null); var promise = store.Dispatch(Helpers.AddTodoAsync("Use Redux")) as Task; await promise.ContinueWith(task => Assert.Equal(2, timesCalled)); }
public void Does_Not_Allow_Unsubscribe_From_Within_Reducer() { var store = Redux.CreateStore(BoundActionInMiddleReducer, 0); var unsubscribe = store.Subscribe(() => { }); Assert.Throws <Exception>(() => { store.Dispatch(new ActionWithBoundFn(unsubscribe)); }); }
public void Does_Not_Allow_Dispatch_From_Within_Reducer() { var store = Redux.CreateStore(Helpers.DispatchInMiddleReducer, 0); Assert.Throws <Exception>(() => { store.Dispatch(new Helpers.ActionWithBoundFn(() => { store.Dispatch(new Helpers.UnknownAction()); })); }); }
public void Does_Not_Allow_GetState_From_Within_Reducer() { var store = Redux.CreateStore(BoundActionInMiddleReducer, 0); Assert.Throws <Exception>(() => { store.Dispatch(new ActionWithBoundFn(() => { store.GetState(); })); }); }
public async void Is_Thread_Safe() { var store = Redux.CreateStore((state, action) => state + 1, 0); await Task.WhenAll( Enumerable .Range(0, 1000) .Select(x => Task.Factory.StartNew(() => store.Dispatch(new UnknownAction())))); Assert.Equal(1001, store.GetState()); }
public void Passes_Initial_Action_And_Initial_State() { var store = Redux.CreateStore(Helpers.TodosReducer, new[] { new Helpers.Todo { Id = 1, Message = "Hello" } }); Assert.Equal(1, store.GetState().Length); Assert.Equal(1, store.GetState().First().Id); Assert.Equal("Hello", store.GetState().First().Message); }
public async void Works_With_Thunk_Middleware() { var store = Redux.ApplyMiddleware(Helpers.Thunk)(Redux.CreateStore)(Helpers.TodosReducer, null); var expectedState = new[] { new Helpers.Todo { Id = 1, Message = "Hello" } }; store.Dispatch(Helpers.AddTodoIfEmpty("Hello")); Assert.Equal(expectedState, store.GetState()); store.Dispatch(Helpers.AddTodoIfEmpty("Hello")); Assert.Equal(expectedState, store.GetState()); expectedState = new[] { new Helpers.Todo { Id = 1, Message = "Hello" }, new Helpers.Todo { Id = 2, Message = "World" } }; store.Dispatch(new Helpers.AddTodoAction("World")); Assert.Equal(expectedState, store.GetState()); expectedState = new[] { new Helpers.Todo { Id = 1, Message = "Hello" }, new Helpers.Todo { Id = 2, Message = "World" }, new Helpers.Todo { Id = 3, Message = "Maybe" } }; var promise = store.Dispatch(Helpers.AddTodoAsync("Maybe")) as Task; await promise.ContinueWith(task => { Assert.Equal(expectedState, store.GetState()); }); }
public void Supports_Multiple_Subscriptions() { var store = Redux.CreateStore(Helpers.TodosReducer, null); var listenerA = new Mock <Action>(); var listenerB = new Mock <Action>(); var unsubscribeA = store.Subscribe(listenerA.Object); store.Dispatch(new Helpers.UnknownAction()); listenerA.Verify(x => x(), Times.Exactly(1)); listenerB.Verify(x => x(), Times.Exactly(0)); store.Dispatch(new Helpers.UnknownAction()); listenerA.Verify(x => x(), Times.Exactly(2)); listenerB.Verify(x => x(), Times.Exactly(0)); var unsubscribeB = store.Subscribe(listenerB.Object); listenerA.Verify(x => x(), Times.Exactly(2)); listenerB.Verify(x => x(), Times.Exactly(0)); store.Dispatch(new Helpers.UnknownAction()); listenerA.Verify(x => x(), Times.Exactly(3)); listenerB.Verify(x => x(), Times.Exactly(1)); unsubscribeA(); listenerA.Verify(x => x(), Times.Exactly(3)); listenerB.Verify(x => x(), Times.Exactly(1)); store.Dispatch(new Helpers.UnknownAction()); listenerA.Verify(x => x(), Times.Exactly(3)); listenerB.Verify(x => x(), Times.Exactly(2)); unsubscribeB(); listenerA.Verify(x => x(), Times.Exactly(3)); listenerB.Verify(x => x(), Times.Exactly(2)); store.Dispatch(new Helpers.UnknownAction()); listenerA.Verify(x => x(), Times.Exactly(3)); listenerB.Verify(x => x(), Times.Exactly(2)); store.Subscribe(listenerA.Object); listenerA.Verify(x => x(), Times.Exactly(3)); listenerB.Verify(x => x(), Times.Exactly(2)); store.Dispatch(new Helpers.UnknownAction()); listenerA.Verify(x => x(), Times.Exactly(4)); listenerB.Verify(x => x(), Times.Exactly(2)); }
// Use this for initialization void Start() { var enhancer = Redux.composeEnhancer(new Redux.Enhancer[] { Redux.applyMiddleware(new Redux.Middleware[] { ReduxMiddleware.createLogger, ReduxMiddleware.createCrashReport }), Redux.Devtools.instrument(this.onChangeMonitoredState) }); this.store = Redux.createStore(TodoList.reducer, null, enhancer); this.store.subscribe(this.onChangeState); this.onChangeState(this.store); }
public void Provides_Up_To_Date_State_When_A_Subscriber_Is_Notified() { var store = Redux.CreateStore(Helpers.TodosReducer, null); store.Subscribe(() => { Assert.Equal(new[] { new Helpers.Todo { Id = 1, Message = "Hello" } }, store.GetState()); }); store.Dispatch(new Helpers.AddTodoAction("Hello")); }
public void Returns_A_Composite_Reducer_That_Maps_The_State_Keys_To_Given_Reducers() { var reducer = Redux.CombineReducers <State, Reducer>(); var state1 = reducer(new State(), new IncrementAction()); Assert.Equal(1, state1.Counter); Assert.Equal(new String[0], state1.Stack); var state2 = reducer(state1, new StackAction { Value = "a" }); Assert.Equal(1, state2.Counter); Assert.Equal(new String[] { "a" }, state2.Stack); }
public void ReturnsACompositeReducerThatMapsTheStateKeysToGivenReducers() { var reducer = Redux.CombineReducers <State, Reducer>(); var state1 = reducer(new State(), new IncrementAction()); Assert.Equal(1, state1.Counter); Assert.Equal(new String[0], state1.Stack); var state2 = reducer(state1, new StackAction { Value = "a" }); Assert.Equal(1, state2.Counter); Assert.Equal(new String[] { "a" }, state2.Stack); }
public void Only_Removes_Listener_Once_When_Unsubscribe_Is_Called() { var store = Redux.CreateStore(Helpers.TodosReducer, null); var listenerA = new Mock <Action>(); var listenerB = new Mock <Action>(); var unsubscribeA = store.Subscribe(listenerA.Object); store.Subscribe(listenerB.Object); unsubscribeA(); unsubscribeA(); store.Dispatch(new Helpers.UnknownAction()); listenerA.Verify(x => x(), Times.Exactly(0)); listenerB.Verify(x => x(), Times.Exactly(1)); }
public void Uses_The_Last_Snapshot_Of_Subscribers_During_Nested_Dispatch() { var store = Redux.CreateStore(Helpers.TodosReducer, null); var listener1 = new Mock <Action>(); var listener2 = new Mock <Action>(); var listener3 = new Mock <Action>(); var listener4 = new Mock <Action>(); Action unsubscribe4 = null; Action unsubscribe1 = null; unsubscribe1 = store.Subscribe(() => { listener1.Object(); listener1.Verify(x => x(), Times.Exactly(1)); listener2.Verify(x => x(), Times.Exactly(0)); listener3.Verify(x => x(), Times.Exactly(0)); listener4.Verify(x => x(), Times.Exactly(0)); unsubscribe1?.Invoke(); unsubscribe4 = store.Subscribe(listener4.Object); store.Dispatch(new Helpers.UnknownAction()); listener1.Verify(x => x(), Times.Exactly(1)); listener2.Verify(x => x(), Times.Exactly(1)); listener3.Verify(x => x(), Times.Exactly(1)); listener4.Verify(x => x(), Times.Exactly(1)); }); store.Subscribe(listener2.Object); store.Subscribe(listener3.Object); store.Dispatch(new Helpers.UnknownAction()); listener1.Verify(x => x(), Times.Exactly(1)); listener2.Verify(x => x(), Times.Exactly(2)); listener3.Verify(x => x(), Times.Exactly(2)); listener4.Verify(x => x(), Times.Exactly(1)); unsubscribe4?.Invoke(); store.Dispatch(new Helpers.UnknownAction()); listener1.Verify(x => x(), Times.Exactly(1)); listener2.Verify(x => x(), Times.Exactly(3)); listener3.Verify(x => x(), Times.Exactly(3)); listener4.Verify(x => x(), Times.Exactly(1)); }
// Use this for initialization void Start() { var finalReducer = Redux.combineReducers(new Redux.Reducer[] { Reducers.todos, Reducers.visibilityFilter }); var enhancer = Redux.composeEnhancer(new Redux.Enhancer[] { Redux.applyMiddleware(new Redux.Middleware[] { ReduxMiddleware.createLogger, ReduxMiddleware.createCrashReport }), Redux.Devtools.instrument(this.onChangeMonitoredState) }); this.store = Redux.createStore(finalReducer, null, enhancer); this.store.subscribe(this.onChangeState); this.onChangeState(this.store); }
public void Wraps_Dispatch_With_Middleware_Once() { var timesCalled = 0; Action stub = () => timesCalled++; var store = Redux.ApplyMiddleware(TestSpy <Helpers.Todo[]>(stub), Helpers.Thunk)(Redux.CreateStore)(Helpers.TodosReducer, null); store.Dispatch(new Helpers.AddTodoAction("Use Redux")); store.Dispatch(new Helpers.AddTodoAction("Flux FTW!")); var state = store.GetState(); Assert.Equal(1, timesCalled); Assert.Equal(2, state.Length); Assert.Equal(1, state[0].Id); Assert.Equal("Use Redux", state[0].Message); Assert.Equal(2, state[1].Id); Assert.Equal("Flux FTW!", state[1].Message); }
public void Supports_Removing_A_Subscription_Within_A_Subscription() { var store = Redux.CreateStore(Helpers.TodosReducer, null); var listenerA = new Mock <Action>(); var listenerB = new Mock <Action>(); var listenerC = new Mock <Action>(); store.Subscribe(listenerA.Object); var unSubB = store.Subscribe(listenerB.Object); store.Subscribe(() => { unSubB(); }); store.Subscribe(listenerC.Object); store.Dispatch(new Helpers.UnknownAction()); store.Dispatch(new Helpers.UnknownAction()); listenerA.Verify(x => x(), Times.Exactly(2)); listenerB.Verify(x => x(), Times.Exactly(1)); listenerC.Verify(x => x(), Times.Exactly(2)); }
public void Applies_The_Reducer_To_The_Initial_State() { var store = Redux.CreateStore(TodosReducer, new[] { new Todo { Id = 1, Message = "Hello" } }); Assert.Equal(new[] { new Todo { Id = 1, Message = "Hello" } }, store.GetState()); store.Dispatch(new UnknownAction()); Assert.Equal(new[] { new Todo { Id = 1, Message = "Hello" } }, store.GetState()); store.Dispatch(new AddTodoAction("World")); Assert.Equal(new[] { new Todo { Id = 1, Message = "Hello" }, new Todo { Id = 2, Message = "World" } }, store.GetState()); }
public void Dispatches_Once_On_Store_Creation() { var store = Redux.CreateStore((state, action) => state + 1, 0); Assert.Equal(1, store.GetState()); }
public void ThrowsErrorIfPublicStatePropertyTypesDoNotPatchPublicStaticReducerMethodReturnTypes() { Assert.Throws <KeyTypeMismatchException>(() => Redux.CombineReducers <NonMatchingStatePropertyTypes, Reducer>()); }
public void Throws_An_Error_If_Public_State_Properties_Do_Not_Match_Public_Static_Reducer_Methods() { Assert.Throws <KeyMismatchException>(() => Redux.CombineReducers <NonMatchingStateProperties, Reducer>()); }
public static void Main() { var initialState = new TodoAppState { DescriptionInput = "", Visibility = TodoVisibility.All, Todos = new Todo[] { new Todo { Id = 0, Description = "Have fun with Ractive and Redux", IsCompleted = true }, new Todo { Id = 1, Description = "Make an awesome todo app", IsCompleted = false } } }; var store = Redux.CreateStore(Todos.Reducer(initialState)); Action <TodoVisibility> show = filter => store.Dispatch(new SetVisibility { Visibility = filter }); // events that are attached to button clicks on the template var eventHandlers = new EventHandlers { ToggleTodo = id => store.Dispatch(new ToggleTodoCompleted { Id = id }), DeleteTodo = id => store.Dispatch(new DeleteTodo { Id = id }), AddTodo = () => store.Dispatch(new AddTodo { }), ShowAll = () => show(TodoVisibility.All), ShowComplete = () => show(TodoVisibility.Completed), ShowIncomplete = () => show(TodoVisibility.YetToComplete) }; // functions that can be called in the template to compute smth directly var functions = new TemplateFunctions { Filter = (visibility, todos) => { if (visibility == TodoVisibility.Completed) { return(todos.Where(todo => todo.IsCompleted).ToArray()); } if (visibility == TodoVisibility.YetToComplete) { return(todos.Where(todo => !todo.IsCompleted).ToArray()); } return(todos); } }; var ractive = new Ractive(new RactiveOptions { Element = "#app", Template = "#app-template", Data = JS.Merge(initialState, functions) }); // although two-way binding is available in Ractive, // I will use a vanilla handler to make data-flow one directional ractive.Find("#txtAddTodo").OnTextChanged(input => { store.Dispatch(new UpdateDescriptionInput { Description = input }); }); // attach the events ractive.On(eventHandlers); store.Subscribe(() => { var state = store.GetState(); ractive.Set(JS.Merge(state, functions)); }); }
public void Preservers_The_State_When_Replacing_A_Reducer() { var store = Redux.CreateStore(Helpers.TodosReducer, null); store.Dispatch(new Helpers.AddTodoAction("Hello")); store.Dispatch(new Helpers.AddTodoAction("World")); Assert.Equal(new[] { new Helpers.Todo { Id = 1, Message = "Hello" }, new Helpers.Todo { Id = 2, Message = "World" } }, store.GetState()); store.ReplaceReducer(Helpers.TodosReducerReverse); Assert.Equal(new[] { new Helpers.Todo { Id = 1, Message = "Hello" }, new Helpers.Todo { Id = 2, Message = "World" } }, store.GetState()); store.Dispatch(new Helpers.AddTodoAction("Perhaps")); Assert.Equal(new[] { new Helpers.Todo { Id = 3, Message = "Perhaps" }, new Helpers.Todo { Id = 1, Message = "Hello" }, new Helpers.Todo { Id = 2, Message = "World" } }, store.GetState()); store.ReplaceReducer(Helpers.TodosReducer); Assert.Equal(new[] { new Helpers.Todo { Id = 3, Message = "Perhaps" }, new Helpers.Todo { Id = 1, Message = "Hello" }, new Helpers.Todo { Id = 2, Message = "World" } }, store.GetState()); store.Dispatch(new Helpers.AddTodoAction("Surely")); Assert.Equal(new[] { new Helpers.Todo { Id = 3, Message = "Perhaps" }, new Helpers.Todo { Id = 1, Message = "Hello" }, new Helpers.Todo { Id = 2, Message = "World" }, new Helpers.Todo { Id = 4, Message = "Surely" } }, store.GetState()); }
// Use this for initialization void Start() { Debug.Log("----------- Add reducers"); var reducers = new Redux.Reducer[] { Reducers.sumResult, Reducers.multiplyResult }; // var type = typeof (Reducers); // var methods = type.GetMethods ( // System.Reflection.BindingFlags.NonPublic | // System.Reflection.BindingFlags.Public | // System.Reflection.BindingFlags.Static | // System.Reflection.BindingFlags.FlattenHierarchy); // // var reducers = new List<Redux.Reducer> (); // foreach (var method in methods) { // if (method.DeclaringType.FullName == type.FullName) { // //reducers // Expression.Lambda<Redux.Reducer> ( // Expression.Call (Expression.Convert (input, o.GetType ()), method), input).Compile (); // } // } this.store = Redux.createStore( Redux.combineReducers(reducers), null, Redux.applyMiddleware(new Redux.Middleware[] { ReduxMiddleware.createThunk, ReduxMiddleware.createLogger, ReduxMiddleware.createCrashReport }) ); Debug.Log("----------- Subscribe"); var unsubscribe = this.store.subscribe(this.onChangeState); { Debug.Log("----------- Dispatch"); this.store.dispatch(ActionCreators.sum(10, 20)); this.store.dispatch(ActionCreators.multiply(10, 20)); Debug.Log("----------- Remove reducers"); Redux.removeReducers(new Redux.Reducer[] { Reducers.multiplyResult }); Debug.Log("----------- Dispatch"); try { this.store.dispatch(ActionCreators.sum(100, 200)); this.store.dispatch(ActionCreators.multiply(100, 200)); } catch (Redux.Error e) { Debug.LogError(e.Message); } } Debug.Log("----------- Unsubscribe"); unsubscribe(); }
public void Does_Not_Allow_Value_TypeActions(Object action) { var store = Redux.CreateStore(Helpers.TodosReducer, null); Assert.Throws <Exception>(() => store.Dispatch(action)); }