Mutik
A tiny (495B) immutable state management library based on Immer
Install / Use
/learn @jaredpalmer/MutikREADME
A tiny (495B) immutable state management library based on Immer
Quick Start
yarn add mutik
or
Table of Contents
<!-- START doctoc generated TOC please keep comment here to allow auto update --> <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --> <!-- END doctoc generated TOC please keep comment here to allow auto update -->Example
To use Mutik with React, you'll need to install React and React DOM from the experimental release channel because Mutik uses the recently-merged useMutableSource hook internally.
yarn add react@experimental react-dom@experimental
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 => ({
...prevState,
count: prevState.count - 1
});
}
// You don't need to pass the store down as a prop either
function Buttons() {
return (
<React.Fragment>
<button onClick={decrement}>-</button>
<button onClick={increment}>+</button>
</React.Fragment>
);
}
// Lastly, you can subcribe to "slices" of state with useSelector
// Note: be sure to memoize these with React.useCallback if you need to select based on props
function Label() {
const selector = React.useCallback(state => state.count, []);
const count = useSelector(selector);
return <p>The count is {count}</p>;
}
render(<App />, window.root);
API
createStore<S>(intialState: S): Store<S>
Create a Mutik store given some initial state. The store has the following API you can use in or out of React.
store
| Method | Description |
| ----------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| get() | Get the current state. Do not use this inside of React, you should instead use useSelector |
| set(nextState: S \| (prevState: S) => V): void; | Set state. This can either take a new value or and updater function (just like React.useState's updater) |
| on(listener: Function): () => void; | Subscribe to store. Pass in a callback function that will be executed on updates. on() returns the unsubscribe function for your convenience. |
| off(listener: Function): void; | Unsubscribe a given listener function |
| reset(): void | Set state back to the initialState used when creating the store |
| mutate(updater: (draft: Draft) => void \| S): void; | Immer-style updater function. |
useSelector<S, V>(selector: (s: S) => V)
React hook to subscribe to Mutik state. Must be called underneath a Mutik Provider.
const selector = state => state.count;
function Label() {
const count = useSelector(selector);
return <p>The count is {count}</p>;
}
You can use props with Mutik selector. For performance, it's a good idea to memoize the selector with React.useCallback. For example:
function User({ id }) {
const selector = React.useCallback(state => state.users[id], [id]);
const user = useSelector(selector);
return <p>The username is {user.name}</p>;
}
<Provider />
Mutik context provider. Pass your store as store prop. For example:
import React from 'react';
import { createStore, Provider } 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>{/* ... stuff */}</div>
</Provider>
);
}
Author
- Jared Palmer @jaredpalmer
Inspiration
MIT License
