Recoil – An Experimental State Management Library for React

Recoil is the State Management Library for React they use at Facebook.

Recoil lets you create a data-flow graph that flows from atoms (shared state) through selectors (pure functions) and down into your React components. Atoms are units of state that components can subscribe to. Selectors transform this state either synchronously or asynchronously

Best to watch the talk from React Europe 2020 embedded above. It clearly explains why Recoil come to exist, and when & how to use it.

If you’ve ever used MobX it might all sound a bit familiar. This Twitter Thread by the MobX author is worth a quick read.

Recoil →

useImmer – A React Hook to use Immer to manipulate state

useImmer(initialState) is very similar to useState. The function returns a tuple, the first value of the tuple is the current state, the second is the updater function, which accepts an immer producer function, in which the draft can be mutated freely, until the producer ends and the changes will be made immutable and become the next state.

import React from "react";
import { useImmer } from "use-immer";


function App() {
  const [person, updatePerson] = useImmer({
    name: "Michel",
    age: 33
  });

  function updateName(name) {
    updatePerson(draft => {
      draft.name = name;
    });
  }

  function becomeOlder() {
    updatePerson(draft => {
      draft.age++;
    });
  }

  return (
    <div className="App">
      <h1>
        Hello {person.name} ({person.age})
      </h1>
      <input
        onChange={e => {
          updateName(e.target.value);
        }}
        value={person.name}
      />
      <br />
      <button onClick={becomeOlder}>Older</button>
    </div>
  );
}

Also comes with an useImmerReducer Hook.

use-immer →

Related: The previously linked Mutik also uses Immer under the hood.

Mutik – A tiny immutable state management library based on Immer

Nice work by Jared Palmer: a React State Management Library which uses Immer internally so you don’t have to worry about overwriting (unrelated) parts of your state whilst updating some value in it.

import React from 'react';
import { render } from 'react-dom';
import { createStore, Provider, useSelector } from 'mutik';
 
// Create a lil' store with some state
let store = createStore({
  count: 0,
});
 
// Pass the store to the Provider.
function App() {
  return (
    <Provider store={store}>
      <div>
        <Label />
        <Buttons />
      </div>
    </Provider>
  );
}
 
// You can mutate the store from anywhere you want to,
// even outside of React code. Mutate is based on immer.
function increment() {
  store.mutate(state => {
    state.count++;
  });
}
 
// Or you can update it like React.useState's update
function decrement() {
  store.set(prevState => ({
    ...state,
    count: state.count - 1
  });
}
 
// You don't need to pass it down as props either,
// although you can if you need to.
function Buttons() {
  return (
    <React.Fragment>
      <button onClick={decrement}>-</button>
      <button onClick={increment}>+</button>
    </React.Fragment>
  );
}
 
function Label() {
  // You can subcribe to "slices" of mutable state with useSelector
  // Note: be sure to memoize these with React.useCallback
  const selector = React.useCallback(state => state.count, []);
  const count = useSelector(selector);
  return <p>The count is {count}</p>;
}
 
render(<App />, window.root);

As you can see in the code example you can use store.set or leverage its power by calling store.mutate which takes an Immer-style updater function as its argument.

Installation per npm/Yarn

yarn add mutik

Mutik Source (GitHub) →
Mutik Demo →

⚠️ Mutik requires experimental builds of react/react-dom as it used the brand spanking new useMutableSource hook which landed only 5 days ago!

yarn add [email protected] [email protected]

Manage React State with zustand

Small, fast and scaleable bearbones state-management solution. Has a comfy api based on hooks, that isn’t boilerplatey or opinionated, but still just enough to be explicit and flux-like.

import create from 'zustand'

const [useStore] = create(set => ({
  count: 1,
  inc: () => set(state => ({ count: state.count + 1 })),
  dec: () => set(state => ({ count: state.count - 1 })),
}))

function Counter() {
  const { count, inc, dec } = useStore()
  return (
    <>
      <h1>{count}</h1>
      <button onClick={inc}>up</button>
      <button onClick={dec}>down</button>
    </>
  )
}

Here’s where things get interesting: To use parts of the store in child components, call the useStore hook, selecting the piece you need from it β€” no providers needed:

function Counter() {
  const count = useStore(state => state.count)
  return <h1>{count}</h1>
}

Installation per NPM/Yarn:

npm install zustand

Zustand – Bear necessities for state management in React →

🌐 In case you don’t get the name: Zustand is German for State.

Unstated β€Šβ€” β€ŠThe setState of React State Management

Unstated is designed to build on top of the patterns already set out by React components and (the new) Context.

Unstated is built upon three pieces that all work together:

  1. Container
  2. <Subscribe>
  3. <Provider>

The idea is that the Container only keeps itself busy with the state. Using <Subscribe> you can link that state to your Component. The <Provider> wraps itself around everything, keeping things together.

import React from 'react';
import { render } from 'react-dom';
import { Provider, Subscribe, Container } from 'unstated';

type CounterState = {
  count: number
};

class CounterContainer extends Container<CounterState> {
  state = {
    count: 0
  };

  increment() {
    this.setState({ count: this.state.count + 1 });
  }

  decrement() {
    this.setState({ count: this.state.count - 1 });
  }
}

function Counter() {
  return (
    <Subscribe to={[CounterContainer]}>
      {counter => (
        <div>
          <button onClick={() => counter.decrement()}>-</button>
          <span>{counter.state.count}</span>
          <button onClick={() => counter.increment()}>+</button>
        </div>
      )}
    </Subscribe>
  );
}

render(
  <Provider>
    <Counter />
  </Provider>,
  document.getElementById('root')
);

Unstatedβ€Šβ€”β€ŠThe setState of React State Management →
Unstated →