Skip to content

A C# implemention of Redux but done in C#. This also contains a WPF abstraction

Notifications You must be signed in to change notification settings

ByronMayne/Redux.DotNet

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Redux Logo

       

Redux Logo




Redux + DotNet

This repository contains a reimplementation of the beloved Redux technoligy used in the the web development world. Redux is a predictable state container for JavaScript C# apps.

Before getting started it is suggested you read up on how Redux works because it matches the usage in this project. Here are a few useful topics to cover.

  • Stores
  • Reducers
  • Middleware
  • Actions
  • Dispatchers

Demo Project

There is currently a demo project in this repo to get it to work you need to run a remote dev instace. To get this running do the following.

  • npm install -g remotedev to install the package globally
  • remotedev to start an instance

Getting Started

It all starts with your application state object. This will contain ever value your application will use.

public record AppState 
{
    public int Counter { get; init; }
}

If you are not using C#9 you can just replace the record with class and remove init and add a constructor to create your type. Records are not required but they simplify the code later on.

Next we have to setup our store. This store will hold our state and manage dispatching of events and mutating of the data, these we will cover later on.

The store should be defined at the start of the application starting up and there should also only ever be a single instace in your application.

IStore<AppState> store = new StoreConfiguration<ApplicationState>()
                      .CreateStore();

This is all you need for the most basic of store however we are going to add some features to allow us to get more ussage.

Action

In redux we need to define actions, actions are the thing that will triger our state to be mutated. We want to define two actions, one to increment our counter and one to decrement it.

public class CounterIncrementByAmount : IAction 
{
    public string Type => "counter/incrementByAmount";
    public int Amount { get; init; }
} 

public class CounterDecrementByAmount : IAction 
{
    public string Type => "counter/incrementByAmount";
    public int Amount { get; init; }
} 

The goal of this actions is to tell the store to change the value of the counter in our state. To do this we need to implement a Reducer.

Reducers

The reducer is what takes the action and figures out how it modifies the state. The state MUST never be edited directly, you should always make a copy and return the new version.

public class CounterReducer : IMiddleware<AppStateT>
{
    public TState Reduce(AppState currentState, IAction action)
    {
        switch (action)
        {
            case CounterIncrementByAmount increment:
            {
                return currentState with { Counter = currentState.Counter + increment.Value  };
            }

            case CounterDecrementByAmount decrement:
            {
                return currentState with { Counter = currentState.Counter + decrement.Value  };
            }
        }
        return currentState;
    }
}

As noted before using the with syntax makes writing this code less of a pain. Now that we have the reducer we need to add it to the store. Lets go back to the initialization logic

IStore<AppState> store = new StoreConfiguration<ApplicationState>()
                      .UserReducer<CounterReducer>()
                      .CreateStore();

XAML Integration

Much like the Javescript version of Redux the WPF version needs to define a provider at the root of the window. A provider is used to provide the store instance to child elements. In the example below the Window has a property called Store which has our store instance.

<Window x:Class="ProfileEditor.MainView">
    <DockPanel LastChildFill="True">
        <StoreProvider Store="{Binding Store}">
            <!-- The content of your window -->
        </StoreProvider>
    </DockPanel>
</Window>

A store is not very useful if it does not have users. Here we are going to add a label to display the value of the counter.

<StoreProvider Store="{Binding Store}">
    <StackPanel Orientation="Horizontal">
        <Label Text="Counter Value: "/>
        <Label Text="{StoreBinding Counter}">
    <StackPanel>
</StoreProvider>

And that is it, the counter now shows the value of the counter and will update when the store changes. Behind the scnes the StoreBinding walks the hierarchy until it finds a StoreProvider and then links to it and subscribes to events.

Now that we are displaying the value lets have a way to increment it

<StoreProvider Store="{Binding Store}">
    <StackPanel Orientation="Horizontal">
        <Label Text="Counter Value: "/>
        <Label Text="{StoreBinding Counter}">
    <StackPanel>
    <StackPanel Orientation="Horizontal">
        <Button Text="+" Command="{ActionBinding IncrementCommand"/>
        <Button Text="-" Command="{ActionBinding IncrementCommand}" />
    <StackPanel>
</StoreProvider>

And now when we press the + or - buttons our counter will increment or decrement.

About

A C# implemention of Redux but done in C#. This also contains a WPF abstraction

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages