I built the simplest react state management library (usecat)
There are so many state management libs for react, but they are too complex / not easy to use for me. I only need these:
Create state for something;
Update the state out of component;
Get the state out of component;
A hook to read state within component;
So I created the lib myself, it's dead simple but very flexible, I have a cat, so I call the lib usecat, github link here. It's so simple that I can list the whole source code here:
import { useEffect, useReducer } from 'react';
const cats = [];
export function createCat(initialValue) {
let value = initialValue;
const listeners = new Set();
const get = () => value;
const set = (newValue) => {
if (newValue !== value) {
const oldValue = value;
value = newValue;
listeners.forEach((listener) => listener(oldValue, newValue));
}
};
const reset = () => set(initialValue);
const subscribe = (listener) => {
listeners.add(listener);
return () => listeners.delete(listener);
};
const cat = { get, set, reset, subscribe };
cats.push(cat);
return cat;
}
export function useCat(cat, selector = (value) => value) {
const [, forceUpdate] = useReducer((x) => x + 1, 0);
useEffect(() => {
const handler = (oldValue, newValue) => {
const oldSlice = selector(oldValue);
const newSlice = selector(newValue);
if (oldSlice !== newSlice) {
forceUpdate();
}
};
const unsubscribe = cat.subscribe(handler);
return () => unsubscribe();
}, [cat]);
return selector(cat.get());
}
Usage is also simple
Create some cats:
import { createCat } from 'usecat';
const isLoadingTodosCat = createCat(false);
const todosCat = createCat([]);
Get and set values out of component:
import { isLoadingTodosCat, todosCat } from './cats';
async function fetchTodos() {
const currentTodos = todosCat.get();
if (currentTodos?.length) {
return;
}
isLoadingTodosCat.set(true);
try {
const response = await fetch('your-fancy-api');
const todos = await response.json();
todosCat.set(todos);
} catch (e) {
// handle error yourself ;)
}
isLoadingTodosCat.set(false);
}
Use hook to get value updates:
import { useCat } from 'usecat';
import { isLoadingTodosCat, todosCat } from './cats'
import { fetchTodos } from './network';
function MyComponent() {
const isLoading = useCat(isLoadingTodosCat);
const todos = useCat(todosCat);
useEffect(() => {
fetchTodos();
}, [])
return (
<>
{isLoading && <div>loading ...</div>}
{todos.map(todo => (
<div key={todo.id}>{todo.title}</div>
))}
</>
)
}
I am using this simple thing to build all my projects, like notenote.cc, check its source code, it's open.