0.2.0 • Published 5 years ago

reason-atomic v0.2.0

Weekly downloads
1
License
MIT
Repository
-
Last release
5 years ago

Atomic

Dead simple shared state in Reason React with a redux-like interface.

Usage

Configure your state by creating a module with state, getInitialState, action, and reducer.

module Config = {
  type state = {count: int};

  let getInitialState = () => {count: 0};

  type action =
    | Increment
    | Decrement
    | NoChange;

  let reducer = state =>
    fun
    | Increment => {count: state.count + 1}
    | Decrement => {count: state.count - 1}
    | NoChange => state;

}; 

Create a new state module with the config

module AppState = Atomic.Make(Config);
// module AppState2 = Atomic.Make(Config);
// module AppState3 = Atomic.Make(Config);

// Create as many instances as you like..

Access the state as a hook, and dispatch actions

[@react.component]
  let make = () => {
    let state = AppState.useState();

    <div>
      {React.string("global count: " ++ string_of_int(state.count))}
      <button onClick={_ => AppState.dispatch(Increment)}> {React.string("+")} </button>
      <button onClick={_ => AppState.dispatch(Decrement)}> {React.string("-")} </button>
    </div>;
  };

If you only care about a subset of the state, you can use useMappedState. This also means that the component with the hook won't re-render unless the state it cares about changes - avoiding excessive re-rendering.

[@react.component]
  let make = () => {
    let count = AppState.useMappedState(state => state.count);

    <div>
      {React.string("global count: " ++ string_of_int(count))}
    </div>;
  };

You can also use the render-props pattern to consume the state as well, using the Consumer component and pass the mapper prop.

[@react.component]
let make = () => {
  <AppState.Consumer mapper={state => state.count}>
    {count => React.string("global count: " ++ string_of_int(count))}
  </AppState.Consumer>;
};