public async Task ExampleUsage2() { var t = Log.MethodEntered("DataStoreExample2.ExampleUsage2"); // Add a thunk middleware to allow dispatching async actions: var thunkMiddleware = Middlewares.NewThunkMiddleware <MyAppState1>(); // aDD A logging middleware to log all dispatched actions: var loggingMiddleware = Middlewares.NewLoggingMiddleware <MyAppState1>(); // Add a recorder middleware to enable hot reload by replaying previously recorded actions: var recorder = new ReplayRecorder <MyAppState1>(); var recMiddleware = recorder.CreateMiddleware(); var undoable = new UndoRedoReducer <MyAppState1>(); // To allow undo redo on the full store wrap the main reducer with the undo reducer: var undoReducer = undoable.Wrap(MyReducers1.ReduceMyAppState1); var data = new MyAppState1(null, null, 0); // the initial immutable state var store = new DataStore <MyAppState1>(undoReducer, data, loggingMiddleware, recMiddleware, thunkMiddleware); store.storeName = "Store 1"; TestNormalDispatchOfActions(store); TestUndoAndRedo(store); await TestAsyncActions(store); await TestReplayRecorder(recorder, store); TestSkippableUndoActions(store); Log.MethodDone(t); }
public async Task ExampleUsage1() { var t = Log.MethodEntered("DataStoreExample3.ExampleUsage1"); // Add a thunk middleware to allow dispatching async actions: var thunkMiddleware = Middlewares.NewThunkMiddleware <MyAppState1>(); // aDD A logging middleware to log all dispatched actions: var loggingMiddleware = Middlewares.NewLoggingMiddleware <MyAppState1>(); var serverOutboxHandler = new ServerOutboxHandler <MyAppState1>(); // To allow undo redo on the full store wrap the main reducer with the undo reducer: var outboxReducer = serverOutboxHandler.Wrap(MyReducers1.ReduceMyAppState1); var initialState = new MyAppState1(); // the initial immutable state var store = new DataStore <MyAppState1>(outboxReducer, initialState, loggingMiddleware, thunkMiddleware); IoC.inject.SetSingleton(store); store.storeName = "Store 3"; { // Do a login which is an async server action that cant be cached optimistically and wont work offline: Func <Task> asyncLoginTask = async() => { await TaskV2.Delay(100); store.Dispatch(new ActionUserLoggedIn() { newLoggedInUser = new MyUser1("*****@*****.**") }); }; await(store.Dispatch(asyncLoginTask) as Task); } { // Change the email a first time: var a = new ActionOnUser.ChangeEmail() { targetEmail = "*****@*****.**", newEmail = "*****@*****.**" }; store.Dispatch(a); Assert.Equal(a, store.GetState().serverOutbox.serverActions.First()); Assert.False(store.GetState().user.emailConfirmed); } { // Change the email a second time: var a = new ActionOnUser.ChangeEmail() { targetEmail = "*****@*****.**", newEmail = "*****@*****.**" }; store.Dispatch(a); Assert.Equal(a, store.GetState().serverOutbox.serverActions.Last()); } Assert.Equal(2, store.GetState().serverOutbox.serverActions.Count); await store.SyncWithServer(store.GetState().serverOutbox.serverActions.First()); Assert.Single(store.GetState().serverOutbox.serverActions); await store.SyncWithServer(store.GetState().serverOutbox.serverActions.First()); Assert.Empty(store.GetState().serverOutbox.serverActions); Assert.True(store.GetState().user.emailConfirmed); { // Simulate a server task that has a timeout: var a = new ActionOnUser.ChangeEmail() { targetEmail = "*****@*****.**", newEmail = "*****@*****.**", simulateOneTimeout = true }; store.Dispatch(a); Assert.Single(store.GetState().serverOutbox.serverActions); Assert.False(store.GetState().user.emailConfirmed); await store.SyncWithServer(a); Assert.Empty(store.GetState().serverOutbox.serverActions); Assert.Equal(2, a.sentToServerCounter); Assert.True(store.GetState().user.emailConfirmed); } { // Simulate the server rejecting an email change: var a = new ActionOnUser.ChangeEmail() { targetEmail = "*****@*****.**", newEmail = "*****@*****.**", simulateError = true }; store.Dispatch(a); await store.SyncWithServer(a); Assert.Empty(store.GetState().serverOutbox.serverActions); Assert.Equal("*****@*****.**", store.GetState().user.email); Assert.True(store.GetState().user.emailConfirmed); } { // Test persisting and restoring the full store and continue with the pending server requests: store.Dispatch(new ActionOnUser.ChangeEmail() { targetEmail = "*****@*****.**", newEmail = "*****@*****.**" }); store.Dispatch(new ActionOnUser.ChangeEmail() { targetEmail = "*****@*****.**", newEmail = "*****@*****.**" }); Assert.Equal(2, store.GetState().serverOutbox.serverActions.Count); Assert.False(store.GetState().user.emailConfirmed); Assert.Equal("*****@*****.**", store.GetState().user.email); // Simulate persisiting the store to disk and back into memory: string persistedStateJson = TypedJsonHelper.NewTypedJsonWriter().Write(store.GetState()); store.Destroy(); // Destroy the old store before loading the state again into an new store var data2 = TypedJsonHelper.NewTypedJsonReader().Read <MyAppState1>(persistedStateJson); var store2 = new DataStore <MyAppState1>(outboxReducer, data2, loggingMiddleware, thunkMiddleware); IoC.inject.SetSingleton(store2, overrideExisting: true); store2.storeName = "Store 3 (2)"; Assert.Equal(2, store2.GetState().serverOutbox.serverActions.Count); Assert.False(store2.GetState().user.emailConfirmed); Assert.Equal("*****@*****.**", store2.GetState().user.email); // Sync the pending server tasks one after another: foreach (var serverAction in store2.GetState().serverOutbox.serverActions) { await store2.SyncWithServer(serverAction); } Assert.True(store2.GetState().user.emailConfirmed); Assert.NotNull(store2.GetState().serverOutbox); Assert.Empty(store2.GetState().serverOutbox.serverActions); } }