Skip to content

rid00z/redux.NET

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Redux.NET

Redux.NET is an attempt to bring Redux concepts to .NET application development. (Only Windows 10 and Android for now, but IOS will come very soon!)

Build Status Nuget

Table of Contents

Motivation

After working on several MVVM applications (Silverlight, WPF, WinRT), I always feel uneasy when they start to get larger :

  • Two-way bindings lead to cascading updates, making it very difficult to predict what would change as the result of a single user interaction.
  • Asynchronous operations make even more laborious to keep the flow of the application in mind.

Dan Abramov, a brilliant javascript developer, faced the same kind of problems with complex web application. His solution? Redux!

The whole state of your app is stored in an object tree inside a single Store. The only way to change the state tree is to emit an Action, an object describing what happened. To specify how the actions transform the state tree, you write pure Reducers.

Installation

You can grab the latest Redux.NET Nuget package or from the NuGet package manager console :

Install-Package Redux.NET

Quick-start

Actions

Actions are payloads of information that send data from your application to your store. They only need to implement the markup interface Redux.IAction.

public class IncrementAction : IAction { }
    
public class DecrementAction : IAction { }
    
public class AddTodoAction : IAction
{
    public string Text { get; set; }
}

Reducers

A reducer is a pure function with ((TState)state, (IAction)action) => (TState)state signature. It describes how an action transforms the state into the next state.

The shape of the state is up to you: it can be a primitive, an array or an object. The only important part is that you should not mutate the state object, but return a new object if the state changes.

namespace Redux.Counter.Universal
{
    public static class CounterReducer
    {
        public static int Execute(int previousState, IAction action)
        {
            if(action is IncrementAction)
            {
                return state + 1;
            }

            if(action is DecrementAction)
            {
                return state - 1;
            }

            return state;
        }
    }
}

Store

The Store<TState> is the class that bring actions and reducer together. The store has the following responsibilities:

  • Holds application state of type TState.
  • Allows state to be updated via Dispatch(IAction action).
  • Registers listeners via Subscribe(IObserver observer). The Store<TState> class implements IObservable so ReactiveExtensions is a usefull tool to observe state changes.

It’s important to note that you’ll only have a single store in a Redux application. In the examples, I keep it as a static property on the application class.

The Store constructor take an initial state, of type TState, and a reducer.

using Redux;
using Windows.ApplicationModel.Activation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace Redux.Counter.Universal
{
    public sealed partial class App : Application
    {
        public static IStore<int> CounterStore { get; private set; }

        public App()
        {
            InitializeComponent();
            
            CounterStore = new Store<int>(initialState:0, reducer:CounterReducer.Execute);
        }
    
        [...]
    }
}

The following code show how to subscribe to a store and to dispatch actions.

using Redux;
using System;
using Windows.UI.Xaml.Controls;
using System.Reactive.Linq;

namespace Redux.Counter.Universal
{
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();

            App.CounterStore.Subscribe(counter => CounterRun.Text = counter.ToString());
        }

        private void IncrementButton_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
        {
            App.CounterStore.Dispatch(new IncrementAction());
        }

        [...]
    }
}

Using DevTools

The development tools contain a time machine debugger inspired by Elm debugger and Redux DevTools.

You can get the dev tools package via nuget or via the Nuget package manager console :

Install-Package Redux.NET.DevTools

To use the time machine, just replace the Store with a TimeMachineStore and the application Frame with a DevFrame:

using Windows.ApplicationModel.Activation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Redux.DevTools.Universal;

namespace Redux.Counter.Universal
{
    public sealed partial class App : Application
    {
        public static IStore<int> CounterStore { get; private set; }

        public App()
        {
            InitializeComponent();
            
            CounterStore = new TimeMachineStore<int>(0, CounterReducer.Execute);
        }

        protected override void OnLaunched(LaunchActivatedEventArgs e)
        {
            Frame rootFrame = Window.Current.Content as Frame;

            if (rootFrame == null)
            {
                rootFrame = new DevFrame
                {
                    TimeMachineStore = (IStore<TimeMachineState>)CounterStore
                };
                Window.Current.Content = rootFrame;
            }

            if (rootFrame.Content == null)
            {
                rootFrame.Navigate(typeof(MainPage), e.Arguments);
            }

            Window.Current.Activate();
        }
    }
}

Examples

About

Redux.NET is a predictable state container for .NET apps. Inspired by https://github.com/rackt/redux.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • C# 96.5%
  • Batchfile 3.5%