Git Product home page Git Product logo

unidux's Introduction

Join the chat at https://gitter.im/Unidux/Lobby

Unidux is practical application architecture for Unity3D UI.

It's inspired by Redux.

Install

Import unitypackage from latest releases.

Usage

  1. Create your Unidux singleton and place it to unity scene.
using UniRx;
using Unidux;

public sealed class Unidux : SingletonMonoBehaviour<Unidux>, IStoreAccessor
{
    public TextAsset InitialStateJson;

    private Store<State> _store;

    public IStoreObject StoreObject
    {
        get { return Store; }
    }

    public static State State
    {
        get { return Store.State; }
    }

    public static Subject<State> Subject
    {
        get { return Store.Subject; }
    }

    private static State InitialState
    {
        get
        {
            return Instance.InitialStateJson != null
                ? JsonUtility.FromJson<State>(Instance.InitialStateJson.text)
                : new State();
        }
    }

    public static Store<State> Store
    {
        get { return Instance._store = Instance._store ?? new Store<State>(InitialState, new Count.Reducer()); }
    }

    public static object Dispatch<TAction>(TAction action)
    {
        return Store.Dispatch(action);
    }

    void Update()
    {
        Store.Update();
    }
}

Note: ReplaySubject is a ReactiveX concept provided by UniRx in this example.

  1. Create state class to store application state.
using System;

[Serializable]
public class State : StateBase
{
    public int Count = 0;
}
  1. Define action to change state. Define Reducer to move state.
public static class Count
{
    // specify the possible types of actions
    public enum ActionType
    {
        Increment,
        Decrement
    }

    // actions must have a type and may include a payload
    public class Action
    {
        public ActionType ActionType;
    }

    // ActionCreators creates actions and deliver payloads
    // in redux, you do not dispatch from the ActionCreator to allow for easy testability
    public static class ActionCreator
    {
        public static Action Create(ActionType type)
        {
            return new Action() {ActionType = type};
        }

        public static Action Increment()
        {
            return new Action() {ActionType = ActionType.Increment};
        }

        public static Action Decrement()
        {
            return new Action() {ActionType = ActionType.Decrement};
        }
    }

    // reducers handle state changes
    public class Reducer : ReducerBase<State, Action>
    {
        public override State Reduce(State state, Action action)
        {
            switch (action.ActionType)
            {
                case ActionType.Increment:
                    state.Count++;
                    break;
                case ActionType.Decrement:
                    state.Count--;
                    break;
            }

            return state;
        }
    }
}
  1. Create Renderer to display state and attach it to Text GameObject.
[RequireComponent(typeof(Text))]
public class CountRenderer : MonoBehaviour
{
    void OnEnable()
    {
        var text = this.GetComponent<Text>();

        Unidux.Subject
            .TakeUntilDisable(this)
            .StartWith(Unidux.State)
            .Subscribe(state => text.text = state.Count.ToString())
            .AddTo(this)
            ;
    }
}
  1. Create dispatcher to update count and attach it to GameObject.
[RequireComponent(typeof(Button))]
public class CountDispatcher : MonoBehaviour
{
    public Count.Action Action = Count.ActionCreator.Increment();

    void Start()
    {
        this.GetComponent<Button>()
            .OnClickAsObservable()
            .Subscribe(state => Unidux.Store.Dispatch(Action))
            .AddTo(this)
            ;
    }
}

That's it!

Example

Dependencies

  • UniRx
  • MiniJSON (for Unidux.Experimental.Editor.StateJsonEditor)

API

StateBase

public class State : StateBase
{
    public int Count;
}

<StateBase>.Clone()

State _state = new State();
State _clonedState = _state.Clone();

Create a deep clone of the current state. Useful for Immutability.

Store

IReducer[] reducers = new IReducer[]{};
Store _store = new Store<State>(State, reducers);
// State must extend StateBase

<Store>.State

Get the state as passed to the constructor.

<Store>.Dispatch(object)

Dispatch an event of TAction object, which will trigger a Reducer<TAction>.

<Store>.ApplyMiddlewares(params Middleware[] middlewares)

Apply middlewares to Store object which implement delegate function of Middleware.

<Store>.Update()

When at least one reducer has been executed, trigger all the renderers with a copy of the current state.

<Store>.ForceUpdate()

Trigger all registered renderers with a copy of the current state regardless of any reducers having been executed.

SingletonMonoBehaviour

public class Foo : SingletonMonoBehaviour<Foo> {}

A singleton base class to extend. Extends MonoBehaviour.

<SingletonMonoBehaviour>.Instance

public class Foo : SingletonMonoBehaviour<Foo> {}

Foo.Instance

The instance of the base class.

Performance

Clone()

Default implemention of StateBase.Clone() is not fast, because it uses BinaryFormatter & MemoryStream. And Unidux creates new State on every State chaning (it affects a few milliseconds). So in case of requiring performance, override clone method with your own logic.

e.g.

[Serializable]
class State : StateBase
{
    public override object Clone()
    {
        // implement your custom deep clone code
    }
}

Equals()

Default implemention of StateBase.Equals() and StateElement.Equals() is not fast, because it uses fields and properties reflection. In case of edit state on UniduxPanel's StateEditor, it calls Equals() in order to set IsStateChanged flags automatically. So in case of requiring performance, override Equals() method with your own logic.

e.g.

[Serializable]
class State : StateBase
{
    public override bool Equals(object obj)
    {
        // implement your custom equality check code
    }
}

Thanks

License

MIT

unidux's People

Contributors

jesstelford avatar kn1cht avatar mattak avatar pine avatar tenmihi avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.