Skip to content

Instantly share code, notes, and snippets.

@domosedov
Last active February 7, 2022 06:43
Show Gist options
  • Save domosedov/839de9970d72487fd984c68b64b1323b to your computer and use it in GitHub Desktop.
Save domosedov/839de9970d72487fd984c68b64b1323b to your computer and use it in GitHub Desktop.
Effector KV
import { createStore, createEvent, type Event, type Store } from "effector";
import { useStoreMap, useEvent } from "effector-react/scope";
import { useCallback } from "react";
type Key = string;
type SetPayload<T> = { key: Key; value: T };
type KeyValueStore<T> = Record<Key, T>;
type KV<T> = {
set: Event<SetPayload<T>>;
remove: Event<Key>;
keyval: Store<KeyValueStore<T>>;
keys: Store<Key[]>;
};
function getValue<T>(
kv: KeyValueStore<T>,
key: Key,
defaultValue: T | null = null
) {
if (key in kv) return kv[key];
return defaultValue;
}
const createKV = <T>(sidPrefix?: string) => {
const $keyval = createStore<KeyValueStore<T>>(
{},
{
sid: sidPrefix ? `${sidPrefix}-keyval` : undefined,
}
);
const set = createEvent<SetPayload<T>>();
const remove = createEvent<Key>();
$keyval.on(set, (kv, { key, value }) => {
if (kv[key] === value) return kv;
return { ...kv, [key]: value };
});
$keyval.on(remove, (kv, key) => {
if (key in kv) {
kv = { ...kv };
delete kv[key];
}
return kv;
});
const $keys = createStore<Key[]>([], {
sid: sidPrefix ? `${sidPrefix}-keys` : undefined,
updateFilter(keys, oldKeys) {
if (keys.length !== oldKeys.length) return true;
return keys.some((key, i) => oldKeys[i] !== key);
},
});
$keys.on($keyval, (_, kv) => Object.keys(kv));
return {
set,
remove,
keyval: $keyval,
keys: $keys,
};
};
function useKVItem<T>(kv: KV<T>, key: Key, initial: T | null = null) {
const value = useStoreMap({
store: kv.keyval,
fn: (kv) => getValue(kv, key, initial),
keys: [key],
});
const [setEvt, removeEvt] = useEvent([kv.set, kv.remove]);
const update = useCallback((value) => setEvt({ key, value }), [kv, key]);
const remove = useCallback(() => removeEvt(key), [kv, key]);
return [value, key, update, remove] as const;
}
export { createKV, useKVItem };
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment