function createStore<T>({ initialState }: { initialState: T }) {
let subscribers: Listener[] = [];
let state = initialState;
const notifyStateChanged = () => {
subscribers.forEach((fn) => fn());
};
return {
subscribe(fn: Listener) {
subscribers.push(fn);
return () => {
subscribers = subscribers.filter((listener) => listener !== fn);
};
},
getSnapshot() {
return state;
},
setState(newState: T) {
state = newState;
notifyStateChanged();
},
};
}
To use the store in react we'll create createUseStore which is a helper that wraps createStore and useSyncExternalStore in a convenient way:
export function createUseStore<T>(initialState: T) {
const store = createStore({ initialState });
return () => [useSyncExternalStore(store.subscribe, store.getSnapshot), store.setState] as const;
}
Counter component:
export const useCountStore = createUseStore(0);
import { useCountStore } from "./countStore";
function Counter() {
const [count, setCount] = useCountStore();
const increment = () => {
setCount(count + 1);
};
const decrement = () => {
setCount(count - 1);
};
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
</div>
);
}
Read more about useSyncExternalStore in the react docs.
To see the implementation of the concepts discussed in this article in action, check out tinystate-react here. This library is built using the approach described in this tutorial, allowing you to dive deeper into the code and examples.