Whoosh - minimalistic React state manager

Related tags

React whoosh
Overview

Whoosh - minimalistic React state manager

Whoosh is a React state manager which entire API consists of exactly one function - createShared().

TL;DR version of the docs

Navigation

Mindset

Whoosh aims to be

  • easy to use and reason about,
  • general and extendable,
  • compact*.

*Whoosh is very small. Its entire source code is under 80 lines (code readability is not sacrificed) and it takes less than 1 Kbyte in minimized form.

Installation

npm install --save whoosh-react

Examples

Counter

This example on codesandbox.io

  1. Create Shared State
// AppState.ts
import { createShared } from 'whoosh-react';

export const appCounter = createShared<number>(0);

createShared() accepts an initial value and returns an object that represents Shared State.

  1. Use Shared State in React components
// Counter.tsx
import { appCounter } from './AppState.ts';

const CounterValue = () => {
    const counter = appCounter.use();
    return <p> { counter } </p>;
};

const CounterControls = () => {
    const reset = () => appCounter.set(0);
    const addOne = () => appCounter.set(previousValue => previousValue + 1);
    return (<>
        <button onClick={reset} > Reset </button>
        <button onClick={addOne} > Add 1 </button>
    </>);
};

In this example we call two function from the appCounter:

  • use() returns current value of the Shared State. It is a React Hook that will trigger component re-render every time Shared State changes.

  • set() is a plain JS function that updates Shared State. It accepts either a new value or a function that returns the new value.

  1. Render the components. They can be anywhere in the tree.
const RootComponent = () => (
    <>
        <A>
            <CounterValue/>
        </A>
        <B>
            <CounterControls/>
        </B>
    </>
);

Counter with Reducer

This example on codesandbox.io

createShared() has the second optional parameter which is a Reducer function.

Reducer is a function of type (previousValue: S, input: A) => S. It describes how Shared State of type S should be modified based on the previousValue and the input. input is the value that was passed to the appCounter.set(). Notice, that if an invalid input is passed to set() a Error will be thrown to the caller of set().

// AppState.ts
export const appCounter = createShared<number, { operation: 'add' | 'subtract' | 'set'; arg: number; }>(
    0,
    (previousValue, { operation, arg }) => {
        switch(operation) {
            case 'add': return previousValue + arg;
            case 'subtract': return previousValue - arg;
            case 'set': return arg;
        }
        // This Error will be thrown to the caller of `appCounter.set(__invalid_parameter__)`
        throw new Error(`appCounter Reducer: operation ${operation} is not supported!`)
    }
);
// Counter.tsx
const CounterControls = () => {
    const reset = () => appCounter.set({operation: 'set', arg: 0});
    const addOne = () => appCounter.set({operation: 'add', arg: 1});
    return (<>
        <button onClick={reset} > Reset </button>
        <button onClick={addOne} > Add 1 </button>
    </>);
};

Passing a function to appCounter.set() is still possible:

const toggleBetween0and1 = () => appCounter.set(
    previousValue => ({
        operation: (previousValue > 0? 'subtract' : 'add'),
        arg: 1
    })
);

Refer to this tutorial on advanced reducer usage in Whoosh.

Most common reducers are available (but completely optional) in the Reducer library

Shared State object API

createShared() returns a Shared State object with the next interface

// S - State type
// A - Reducer input type (if Reducer is present)

interface SharedState<S, A = S> {
    use(): S;                                   // React Hook that returns current state value
    get(): S;                                   // Getter
    set(a: A | ((s: S) => A)): void;            // Setter / Dispatcher
    on(cb: (state: S) => void): () => void;     // Subscribe on the state change, returns unsubscribe function
    off(cb: (state: S) => void): void;          // Unsubscribe off the state change
}
  • use() is a React Hook that will trigger component re-render when the Shared State changes. It is subject to React Hook usage rules, just like any other Hook. It can only be called from the inside of a functional component.

All other functions are plain js functions. They can be called from anywhere.

  • get() gets current Shared State value. It is not allowed to directly modify the returned value in any way. Use set() instead.

  • set() updates Shared State value. Accepts either a new value or a function that accepts previous value and returns the new value. The new value should be of type S if no reducer is passed to createShared() or of type A if there is. (Of course, nothing prevents you having S === A which is a very useful case by itself.) The call of the function will trigger re-render of the components that are mounted and use() this Shared State.

  • on() and off() allow to manually subscribe and unsubscribe to/from Shared State changes. See Shared State Interaction for usage example.

All SharedState functions are guaranteed to be stable. Itโ€™s safe to omit them from the useEffect or other hooks dependency lists.

All SharedState functions do NOT require bind. They are really just functions and NOT class methods.

createShared() function API

// S - State type
// A - Reducer input type (if Reducer is present)
// I - Initializer input type (if Reducer and Initializer are both present)

type Reducer<S, A> = (previousState: S, input: A) => S;
type ReducerAndInit<S, A, I> = [ Reducer<S, A>, (initArg: I) => S ];
type ReducerOrReducerWithInit<S, A> = Reducer<S, A> | ReducerAndInit<S, A, S>;

function createShared<S>(initValue: S, reducer?: ReducerOrReducerWithInit<S, S>): SharedState<S, S>;
function createShared<S, A>(initValue: S, reducer: ReducerOrReducerWithInit<S, A>): SharedState<S, A>;
function createShared<S, A, I>(initValue: I, reducer: ReducerAndInit<S, A, I>): SharedState<S, A>;

createShared() takes two arguments: an initialValue (required) and a reducer (optional).

The reducer is either a Reducer function or a tuple (an array) of two functions, first of which is a Reducer and second is an Initializer.

Usage with class components

Whoosh primarily targets the "new way" of doing thins in React. That is, when the entire application is build using only functional components. But, if you have to support a class component, you can manually subscribe on() the Shared State change in componentWillMount() and unsubscribe off() the Shared State change in componentWillUnmount().

Changelog

1.0.8

  • Improve toLocalStorage() typing

1.0.8

  • Update docs
  • Add reducer partialUpdate

1.0.6

  • Improve reducer-compose typing

1.0.5

  • Add reducers arrayOp and setOp to the reducer library and update docs accordingly
  • Underlying state object is now freezed in order to prevent modifications

1.0.4

  • Add initializer function to the reducer argument of createShared()
  • Add reducer library:
    • toLocalStorage() reducer
    • compose() - a function for reducer composition
  • Build with rollup

1.0.1

  • Initial release

License

ยฉ github.com/AlexIII

MIT

You might also like...

A document head manager for React

A document head manager for React

React Helmet This reusable React component will manage all of your changes to the document head. Helmet takes plain HTML tags and outputs plain HTML t

Dec 30, 2022

Real state property listing app using next.js , chakra.ui, SCSS

Real state property listing app using next.js , chakra.ui, SCSS

This is a Next.js project bootstrapped with create-next-app. Getting Started First, run the development server: npm run dev # or yarn dev Open http://

Dec 19, 2021

This hook allows you to isolate and manage the state within the component, reducing rendering operations and keeping the source code concise.

React Hook Component State This hook allows you to isolate and manage the state within the component, reducing rendering operations and keeping the so

May 15, 2022

๐Ÿ”ฎ tiny robust state management

๐Ÿ”ฎ snapstate tiny robust state management ๐Ÿ“ฆ npm install @chasemoskal/snapstate ๐Ÿ‘๏ธ watch for changes to properties ๐Ÿ•ต๏ธ track only the properties you

Dec 23, 2022

A tiny package for JavaScript Web App's state management based on RxJS & Immer

A tiny package for JavaScript Web App's state management based on RxJS & Immer

Oct 19, 2022

Tiny and powerful state management library.

Tiny and powerful state management library.

BitAboutState Tiny and powerful React state management library. 100% Idiomatic React. Install npm install --save @bit-about/state Features 100% Idioma

Nov 5, 2022

๐Ÿ–ฑor โŒจ๏ธ? ๐Ÿคทโ€โ™€๏ธ, but hopefully use-hover-state works on the "user intent" not the "device"

useHoverState() The one aware of keyboard navigation as well ๐Ÿ˜‰ npm i use-hover-state A React hook for tracking user interaction with the DOM elements

Aug 11, 2022

Learning how to use redux - a state management library

Learning how to use redux - a state management library

Redux Learning how to use redux - a state management library What is Redux? Redux is a state management library for JS apps. It centralizes applicatio

Jul 18, 2022

a babel plugin that can transform generator function to state machine, which is a ported version of typescript generator transform

Babel Plugin Lite Regenerator intro This babel plugin is a ported version of TypeScript generator transform. It can transform async and generator func

Jul 8, 2022
Owner
Alexander Blk
Embedded system hardware/software engineer
Alexander Blk
Recoil is an experimental state management library for React apps. It provides several capabilities that are difficult to achieve with React alone, while being compatible with the newest features of React.

Recoil ยท Recoil is an experimental set of utilities for state management with React. Please see the website: https://recoiljs.org Installation The Rec

Facebook Experimental 18.2k Jan 8, 2023
A Higher Order Component using react-redux to keep form state in a Redux store

redux-form You build great forms, but do you know HOW users use your forms? Find out with Form Nerd! Professional analytics from the creator of Redux

Redux Form 12.6k Jan 3, 2023
๐Ÿป Bear necessities for state management in React

A small, fast and scaleable bearbones state-management solution. Has a comfy api based on hooks, isn't boilerplatey or opinionated, but still just eno

Poimandres 25.5k Jan 9, 2023
๐Ÿ High performance subscription-based form state management for React

You build great forms, but do you know HOW users use your forms? Find out with Form Nerd! Professional analytics from the creator of React Final Form.

Final Form 7.2k Jan 7, 2023
A state management library for React, heavily inspired by vuex

Vuex - But for React! โš› If you know vuex, you know it's as close as we get to a perfect state management library. What if we could do this in the reac

Dana Janoskova 103 Sep 8, 2022
experimental project for babel-plugin-mutable-react-state

Goalist Mutable React Example This example is an attempt to work with babel-plugin-mutable-react-state on a simpler project to see how complicated wou

Reaper 1 Jun 7, 2022
Twitter-Clone-Nextjs - Twitter Clone Built With React JS, Next JS, Recoil for State Management and Firebase as Backend

Twitter Clone This is a Next.js project bootstrapped with create-next-app. Getting Started First, run the development server: npm run dev # or yarn de

Basudev 0 Feb 7, 2022
React Native's Global Alert Component that can be fully customized and without the need of a state.

?? React Native Easy Alert React Native Easy Alert Component. Watch on youtube Easy Alert example app. React Native's Global Alert Component that can

null 9 Feb 21, 2022
Small (0.5 Kb) react hook for getting media breakpoints state info in runtime

tiny-use-media Small (0.5 Kb) react hook for getting media breakpoints state info in runtime Usage npm i tiny-use-media --save Adn in your react code

Valeriy Komlev 51 Dec 13, 2022
Edvora App is a web application based on an external API, showing data about different types of products and the user can filter these data by choosing a specific state, city or product name. Build with React.js

Edvora App is a web application based on an external API, showing data about different types of products and the user can filter these data by choosing a specific state, city or product name. Build with React.js

Kyrillos Hany 5 Mar 11, 2022