Options
All
  • Public
  • Public/Protected
  • All
Menu

Module @lauf/store-react

Lightweight React Application State Management

codecov

Logo - Image of Runner

Lauf Store React

Logo - Diego Naive, Noun Project.

Install

npm install @lauf/store-react --save

@lauf/store-react enables React apps to use @lauf/store for state-management, providing a simple substitute for Flux/Redux based on Immer.

Browse the API or the Typescript example inlined below from our Counter App.

The Counter example below shows how useSelected binds a selected part of a Store's state to a component, and how events can edit the state.

You can see the app running in an online sandbox; in javascript, or in typescript.

App Behaviour

  • AppState defines the state structure for the Store.
  • StoreProps passes the Store to React components.
  • The Display React component has a useSelected hook to re-render when counter changes.
  • The Increment and Decrement buttons don't re-render on any state changes, but they DO trigger an edit to the counter state when clicked.
  • App calls useStore passing in an INITIAL_STATE to initialise a Store on first load.
  • App inserts the three components, passing each one the store to do its work.
import React from "react";
import ReactDOM from "react-dom";
import { Store, Immutable } from "@lauf/store";
import { useStore, useSelected } from "@lauf/store-react";

interface AppState {
  counter: number;
}

const INITIAL_STATE: Immutable<AppState> = {
  counter: 0,
} as const;

interface StoreProps {
  store: Store<AppState>;
}

const Display = ({ store }: StoreProps) => {
  const counter = useSelected(store, (state) => state.counter);
  return <h1>{counter}</h1>;
};

const Increment = ({ store }: StoreProps) => (
  <button onClick={() => store.edit((draft) => (draft.counter += 1))}>
    Increase
  </button>
);

const Decrement = ({ store }: StoreProps) => (
  <button onClick={() => store.edit((draft) => (draft.counter -= 1))}>
    Decrease
  </button>
);

const App = () => {
  const store = useStore(INITIAL_STATE);
  return (
    <>
      <Display store={store} />
      <Increment store={store} />
      <Decrement store={store} />
    </>
  );
};

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById("root")
);

Index

Functions

useRootState

useSelected

  • A hook for tracking a subpart or a computed value derived from the RootState of a Store by a Selector function.

    This hook calls selector with the Store's RootState and returns the derived value. Then it watches the store, calling the selector again for every change to the RootState. If the value returned by selector is not identical to the last saved value, a re-render will be triggered (and this hook will return the new value).

    If your selector constructs a new data structure based on the RootState, (rather than just selecting some part of the Immutable RootState or calculating a primitive value), then it might return a non-identical value even when nothing has changed. Computed data structures should be memoized to minimise component refreshes.

    See Selector

    Type parameters

    • State: object

    • Selected

    Parameters

    Returns Immutable<Selected>

useStore

  • When the component is first mounted, this hook creates and returns a a new long-lived Store initialised with initialState.

    In later renders the hook will always return the same Store, It deliberately doesn't force a component refresh when the Store state changes. To track changes in the store, see useSelected or useRootState.

    Type parameters

    • T: object

    Parameters

    Returns Store<T>

    A lazily-created Store

Generated using TypeDoc