hadashiA / UniMob

Reactive state management for Unity

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

UniMob Github license Unity 2019.3 GitHub package.json version

Reactive state management for Unity

Introduction

UniMob is a library that makes state management simple and scalable by transparently applying functional reactive programming. The philosophy behind UniMob is very simple:

Anything that can be derived from the application state, should be derived. Automatically.

which includes the UI, data serialization, server communication, etc.

A quick example

So what does code that uses UniMob look like?

using UniMob;
using UnityEngine;
using UnityEngine.UI;

public class Counter : MonoBehaviour
{
    public Text counterText;
    public Button incrementButton;

    // declare observable property
    [Atom] private int Counter { get; set; }

    private void Start()
    {
        // increment Counter on button click
        incrementButton.onClick.AddListener(() => Counter += 1);
        
        // Update counterText when Counter changed
        Atom.Reaction(() => counterText.text = "Tap count: " + Counter);
    }
}

Core concepts

UniMob has only a few core concepts.

Observable state

UniMob adds observable capabilities to existing data. This can simply be done by annotating your class properties with the [Atom] attribute.

using UniMob;

public class Todo
{
    [Atom] public string Title { get; set; } = "";
    [Atom] public bool Finished { get; set; } = false;
}

Using [Atom] is like turning a property of an object into a spreadsheet cell that when modified may cause other cells to automatically recalculate or trigger reactions.

Computed values

With UniMob you can define values that will be derived automatically when relevant data is modified.

using UniMob;
using System.Linq;

public class TodoList
{
    [Atom] public Todo[] Todos { get; set; } = new Todo[0];
    [Atom] public int UnfinishedTodoCount => Todos.Count(todo => !todo.Finished);
}

UniMob will ensure that UnfinishedTodoCount is updated automatically when a todo is added or when one of the finished properties is modified. Computations like these resemble formulas in spreadsheet programs like MS Excel. They update automatically and only when required.

Reactions

Reactions are similar to a computed value, but instead of producing a new value, a reaction produces a side effect for things like printing to the console, making network requests, updating the UniMob.UI widgets, etc. In short, reactions bridge reactive and imperative programming.

UniMob.UI widgets

If you are using UniMob.UI, you can use observable state in your widgets. UniMob will make sure the interface are always re-rendered whenever needed.

public class TodoListApp : UniMobUIApp
{
    private TodoList todoList = new TodoList();

    protected override Widget Build(BuildContext context)
    {
        return new Column {
            Children = {
                new UniMobText(WidgetSize.FixedHeight(60)) {
                    Value = "Tasks left: " + todoList.UnfinishedTodoCount
                },
                todoList.Todos.Select(todo => BuildTodo(todo))
            }
        };
    }

    private Widget BuildTodo(Todo todo)
    {
        return new UniMobButton {
            OnClick = () => todo.Finished = !todo.Finished,
            Child = new UniMobText(WidgetSize.FixedHeight(60)) {
                Value = todo.Title + ": " + (todo.Finished ? "Finished" : "Active")
            }
        };
    }
}

Custom reactions

Custom reactions can simply be created using the Reaction or When methods to fit your specific situations.

For example the following Reaction prints a log message each time the amount of UnfinishedTodoCount changes:

Atom.Reaction(() => {
    Debug.Log("Tasks left: " + todoList.UnfinishedTodoCount);
});

What will UniMob react to?

Why does a new message get printed each time the UnfinishedTodoCount is changed? The answer is this rule of thumb:

UniMob reacts to any existing observable property that is read during the execution of a tracked function.

Actions

UniMob is unopinionated about how user events should be handled.

  • This can be done with Tasks.
  • Or by processing events using UniRx.
  • Or by simply handling events in the most straightforward way possible.

In the end it all boils down to: Somehow the state should be updated.

After updating the state UniMob will take care of the rest in an efficient, glitch-free manner. So simple statements, like below, are enough to automatically update the user interface.

todoList.Todos = todoList.Todos
    .Append(new Todo("Get Coffee"))
    .Append(new Todo("Write simpler code"))
    .ToArray();
todoList.Todos[0].Finished = true;

How to Install

Minimal Unity Version is 2019.3.

Library distributed as git package (How to install package from git URL)
Git URL: https://github.com/codewriter-packages/UniMob.git

License

UniMob is MIT licensed.

Credits

UniMob inspired by $mol_atom and MobX.

About

Reactive state management for Unity

License:MIT License


Languages

Language:C# 100.0%