/redux-rs

:package: A Rust implementation of Redux.

Primary LanguageRustMIT LicenseMIT

Build Status Crates.io Documentation Code Coverage

redux-rs

A Rust implementation of Redux.

Redux

Redux, originally implemented in JavaScript, is an functional approach to state management. The core concept is that you have a state and a reducer, a function to create a new state from the old one and an action, a description of what to change. Because the state itself is immutable, this results in a very clean way of managing application state, where every possible action is defined beforehand and dispatched later on.

Usage

You might want to read the documentation, which also provides examples.

Also consider checking out the examples.

To run an example:

cargo run --example <name of the example>

To jump right into it, here is the simple counter example from examples/counter.rs:

use redux_rs::{Store, Subscription};

#[derive(Default)]
// This is a state. It describes an immutable object.
// It is changed via a 'reducer', a function which receives an action and returns a new state modified based on the action.
struct State {
    counter: i8
}

// The actions describe what the reducer has to do.
// Rust enums can carry a payload, which one can use to pass some value to the reducer.
enum Action {
    Increment,
    Decrement
}

// Here comes the reducer. It gets the current state plus an action to perform and returns a new state.
fn counter_reducer(state: &State, action: &Action) -> State {
    match action {
        Action::Increment => State {
            counter: state.counter + 1
        },
        Action::Decrement => State {
            counter: state.counter - 1
        }
    }
}

fn main() {
    // A store is a way to handle a state. It gets created once and after that it can be read and changed via dispatching actions.
    let mut store = Store::new(counter_reducer, State::default());

    // A listener getting triggered whenever the state changes.
    let listener: Subscription<State> = |state: &State| {
        println!("Counter changed! New value: {}", state.counter);
    };

    // Listener gets subscribed to the store.
    store.subscribe(listener);

    // Now, let's dispatch some actions!
    store.dispatch(Action::Increment);
    store.dispatch(Action::Increment);
    store.dispatch(Action::Increment);
    store.dispatch(Action::Decrement);
    store.dispatch(Action::Decrement);

    // Retrieve the value at any time.
    println!("Final value: {}", store.state().counter);
}

no_std support

redux-rs supports the no_std feature via disabling the default features.

Note: This requires a nightly compiler and the availability of the alloc crate for the target.

In your Cargo.toml:

[dependencies]
redux-rs = { version = "...", default-features = false }

Benchmarks

Running benchmarks requires a nightly compiler.

cargo +nightly bench
test counter_decrement                         ... bench:           2 ns/iter (+/- 0)
test counter_increment_with_reverse_middleware ... bench:           6 ns/iter (+/- 0)
test counter_increment_with_subscription       ... bench:           3 ns/iter (+/- 0)