@mongez/react-atom
Version:
A simple state management tool for React Js.
99 lines (96 loc) • 2.82 kB
JavaScript
"use client";
import { useAtom } from "./store.mjs";
import { useCallback, useEffect, useSyncExternalStore } from "react";
import { atomCollection, createAtom } from "@mongez/atom";
//#region ../@mongez/react-atom/src/react-atom.tsx
/**
* Build the React-aware action bag injected into every atom created via
* the `atom()` factory in this package.
*
* Every hook in here goes through `useAtom(this)` first so that
* components rendered inside an `<AtomStoreProvider>` operate on the
* store-scoped clone, not the module-level template.
*
* Subscriptions are wired through `useSyncExternalStore` to keep React 18+
* concurrent rendering tear-free.
*/
function reactActions(data) {
return {
...data.actions,
Provider(props) {
const atom = useAtom(this);
useEffect(() => {
atom.update(props.value);
}, [props.value, atom]);
return props.children;
},
useWatch(key, callback) {
const atom = useAtom(this);
useEffect(() => {
const sub = atom.watch(key, callback);
return () => sub.unsubscribe();
}, [
atom,
key,
callback
]);
},
useState() {
const atom = useAtom(this);
const subscribe = useCallback((onChange) => {
const sub = atom.onChange(onChange);
return () => sub.unsubscribe();
}, [atom]);
const getSnapshot = useCallback(() => atom.value, [atom]);
return [useSyncExternalStore(subscribe, getSnapshot, getSnapshot), useCallback((next) => {
atom.update(next);
}, [atom])];
},
useValue() {
const atom = useAtom(this);
const subscribe = useCallback((onChange) => {
const sub = atom.onChange(onChange);
return () => sub.unsubscribe();
}, [atom]);
const getSnapshot = useCallback(() => atom.value, [atom]);
return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
},
use(key) {
const atom = useAtom(this);
const subscribe = useCallback((onChange) => {
const sub = atom.watch(key, onChange);
return () => sub.unsubscribe();
}, [atom, key]);
const getSnapshot = useCallback(() => atom.get(key), [atom, key]);
return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
}
};
}
/**
* Create a new React-aware atom.
*
* The returned atom carries hooks (`useState`, `useValue`, `use`, `useWatch`)
* and a `<Provider>` component as instance methods. All hooks honor the
* nearest `<AtomStoreProvider>` and use `useSyncExternalStore` underneath.
*/
function atom(data) {
return createAtom({
...data,
actions: reactActions(data)
});
}
/**
* Create a React-aware collection atom for working with arrays.
*/
function atomCollection$1(options) {
return atomCollection({
...options,
actions: {
...options.actions,
...reactActions(options)
}
});
}
//#endregion
export { atom, atomCollection$1 as atomCollection };
//# sourceMappingURL=react-atom.mjs.map