Awesome
Reducto is a port of Redux to .NET
What is Reducto?
Reducto is a keeper of the state for your app. It helps to organize the logic that changes that state. Really useful for GUI apps in combination with(but not limited to) MVVM, MVC, MVP etc.
Metric | Value |
---|---|
lines of code | ~260 |
dependencies | 0 |
packaging | NuGet PCL |
Installation
In Package Manager Console run
PM> Install-Package Reducto
Key concepts
- Action - an object which describes what has happened - LoggedIn, SignedOut, etc. The object contains all the information relevant to the action - username, password, status, etc. Usually there are many actions in an app.
- Reducer - a side-effect free function that receives the current state of your app and an
action
. If the reducer does not know how to handle theaction
it should return the state as is. If the reducer can handle theaction
it 1.) makes a copy of the state 2.) it modifies it in response to theaction
and 3.) returns the copy. - Store - it is an object that contains your app's state. It also has a
reducer
. We dispatch anaction
to thestore
which hands it to thereducer
together with the current app state and then uses the return value of thereducer
as the new state of the app. There is only onestore
in your app. It's created when your app starts and gets destroyed when your app quits. Your MVVM view models can subscribe to be notified when the state changes so they can update themselves accordingly. - Async action - a function that may have side effects. This is where you talk to your database, call a web service, navigate to a view model, etc.
Async actions
can also dispatchactions
(as described above). To execute anasync action
it needs to be dispatched to thestore
. - Middleware - these are functions that can be hooked in the
store
dispatch mechanism so you can do things like logging, profiling, authorization, etc. It's sort of a plugin mechanism which can be quite useful.
Dispatching an action
to the store is the only way to change its state.<br>
Dispatching an async action
cannot change the state but it can dispatch actions
which in turn can change the state.
How does one use this thing?
Here is a short example of Reducto in action. Let's write an app that authenticates a user.
First, let's define the actions
that we will need:
// Actions
public struct LoginStarted
{
public string Username;
}
public struct LoginFailed {}
public struct LoginSucceeded
{
public string Token;
}
Next is the state of our app
// State
public enum LoginStatus
{
LoginInProgress, LoggedIn, NotLoggedIn
}
public struct AppState
{
public LoginStatus Status;
public String Username;
public String Token;
}
Here is how the actions
change the state of the app
var reducer = new SimpleReducer<AppState>()
.When<LoginStarted>((state, action) => {
state.Username = action.Username;
state.Token = "";
state.Status = LoginStatus.LoginInProgress;
return state;
})
.When<LoginSucceeded>((state, action) => {
state.Token = action.Token;
state.Status = LoginStatus.LoggedIn;
return state;
})
.When<LoginFailed>((state, action) => {
state.Status = LoginStatus.NotLoggedIn;
return state;
});
var store = new Store<AppState>(reducer);
Now let's take a moment to see what is going on here. We made a reducer
using a builder and define how each action
changes the state. This reducer
is provieded to the store
so the store can use it whenever an action
is dispatched to it. Makes sense so far? I hope so ;)
Now let's see what is dispatching actions
to the store
. One can do that directly but more often then not it will be done from inside an async action
like this one
var loginAsyncAction = store.asyncAction(async(dispatch, getState) => {
dispatch(new LoginStarted{Username = "John Doe"});
// faking authentication of user
await Task.Delay(500);
var authenticated = new Random().Next() % 2 == 0;
if (authenticated) {
dispatch(new LoginSucceeded{Token = "1234"});
} else {
dispatch(new LoginFailed());
}
return authenticated;
});
A lot going on here. The async action
gets a dispatch and a getState delegates. The latter one is not used in our case but the former is used a lot. We dispatch an action to signal the login process has started and then again after it has finished and depending on the outcome of the operation. How do we use this async action
?
store.Dispatch(loginAsyncAction);
// or if you need to know the result of the login you can do also
var logged = await store.Dispatch(loginAsyncAction);
For more examples and please checkout the links below in the Resources section
Resources
A couple of links on my blog