Automatons is a React/JavaScript side effect management library based on finite state machines that enables you to keep your logic clear by describing it formally in terms of automata theory.
- The Why
- Installation
- Getting Started
- 3.1. Basic Usage
- 3.2. React Binding
- 3.3. Timers
- 3.4. Advanced Side Effects
- API Documentation
- Contributing
View layer logic often tends to get messy, especially when dealing with asynchronous external events from network or complex animations and user input.
State machines help to untangle the spaghetti logic as it is described formally as a series of states, transitions and side effects.
- Installation:
npm i automatons
- CDN:
- AMD module: https://unpkg.com/automatons@0.0.4/dist/automatons.amd.js
- CommonJS module: https://unpkg.com/automatons@0.0.4/dist/automatons.cjs.js
- EcmaScript module: https://unpkg.com/automatons@0.0.4/dist/automatons.esm.js
A state machine is an abstract mechanism that is capable of remembering it's current state and changing it according to a pre-determined set of rules.
Automatons library provides a function to construct such state machines:
import {automaton} from "automatons";
const stateMachine = automaton([
/* List of transition rules go here */
])
(See 01: Basic Usage on codesandbox.io)
A state machine can be defined by three components:
- a list of all possible states;
- a list of rules to change the remembered state;
- an initial state.
All Automatons state machines start in a special INITIAL
state, reference
to which is provided by the library:
import {INITIAL} from "automatons";
Transitions is Automatons library are triggered by external events
called signals and are described by transition
function:
import {automaton, transition, INITIAL} from "automatons";
const stateMachine = automaton([
/**
* Transitioning from INITIAL state to "clicked" on any signal
*/
transition(INITIAL, () => "clicked"),
/**
* Transitioning from "clicked" state back to INITIAL on "reset" signal
*/
transition("clicked", "reset", INITIAL),
]);
// Triggering the transition
stateMachine.transition("");
console.log(stateMachine.state); // "clicked"
// Triggering it again!
stateMachine.transition("reset");
console.log(stateMachine.state); // INITIAL
(See 02: React Binding on codesandbox.io)
Automatons library provides bindings to React to make possible the usage of state machines in view layer logic.
You can add a state machine to any React component by applying a
@withAutomaton
decorator:
import {withAutomaton} from "automatons";
@withAutomaton
class Button extends React.Component {
transitions = [
/* List of state machine transitions */
]
}
Automatons supports automatic state mapping and automatic component updates
with the help of mapToState
parameter:
import {withAutomaton} from "automatons";
@withAutomaton({
mapToState: "phase",
})
class Button extends React.Component {
/**
* Now this.state.phase always refers to the current automaton state
*/
}
It is also possible to automatically bind React event callbacks to automaton
signals with the help of asSignal
:
import {withAutomaton, asSignal} from "automatons";
@withAutomaton
class Button extends React.Component {
render() {
return (
<button onClick={asSignal(this, "click")}>
Click me!
</button>
);
}
}
(See 03: State Mapping & Timers on codesandbox.io)
One of the most prominent features of Automatons is the ability to perform transitions automatically after a timeout:
import {automaton, timer, INITIAL} from "automatons";
const stateMachine = automaton([
/**
* Transitioning from INITIAL state to "ready" in 100 milliseconds
*/
timer(INITIAL, 100, "ready"),
/**
* Transitioning from "ready" state to "sleeping" in 4 seconds
*/
timer("ready", 4000, "sleeping"),
]);
(See 04: Advanced Side Effects on codesandbox.io)
It is possible to perform a side effect that does not trigger any state change:
import {automaton, transition, sideEffect, INITIAL} from "automatons";
const stateMachine = automaton([
/**
* Side effect will be performed if in INITIAL state and "click" signal
* is dispatched
*/
sideEffect(INITIAL, "click", () => {
alert("Clicked!");
}),
/**
* And that side effect does not stop the transition from INITIAL to
* "clicked" on the same signal from happening.
*/
transition(INITIAL, "click", "clicked"),
]);
For further information please refer to API Documentation.
When contributing to Automatons, please open an issue first.
Please note the code of conduct, it is desired to follow it in all your interactions with the project.
When reporting a bug, please provide a minimal case of reproduction, which can be:
- a test that is broken but should not be,
- a Codesandbox project in which the bug occurs.
When sending a pull request, please do not forget the following:
- resolve all conflicts with
master
branch, - update the README.md and/or the documentation in comments according to your changes,
- ensure the documentation build is up-to-date in
docs
folder, - ensure the new functionality is covered by tests, and all tests pass.