@oimdb/react
Version:
React integration for OIMDB - Hooks for selection and subscription with external storage
280 lines (278 loc) • 8.88 kB
JavaScript
// src/hooks/index.ts
import { useMemo, useRef } from "react";
import { useSyncExternalStore } from "react";
var EMPTY_ARRAY = [];
var useSelectPksByIndexKeysSetBased = (reactiveIndex, keys) => {
const prevKeysRef = useRef();
const keysAreEqual = arraysEqual(prevKeysRef.current || EMPTY_ARRAY, keys);
if (!keysAreEqual) {
prevKeysRef.current = keys;
}
const snapshotValueRef = useRef();
const subscribe = useMemo(() => {
snapshotValueRef.current = keys.map((key) => Array.from(reactiveIndex.getPksByKey(key))).flat();
return (onStoreChange) => {
const prevKeys = prevKeysRef.current;
if (!prevKeys) {
return () => {
};
}
const updateSnapshot = () => {
snapshotValueRef.current = keys.map((key) => Array.from(reactiveIndex.getPksByKey(key))).flat();
onStoreChange();
};
reactiveIndex.updateEventEmitter.subscribeOnKeys(
prevKeys,
updateSnapshot
);
return () => {
reactiveIndex.updateEventEmitter.unsubscribeFromKeys(
prevKeys,
updateSnapshot
);
};
};
}, [prevKeysRef.current, reactiveIndex.updateEventEmitter]);
const getSnapshot = useMemo(() => {
return () => {
return snapshotValueRef.current;
};
}, []);
const snapshot = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
return snapshot;
};
var useSelectPksByIndexKeySetBased = (reactiveIndex, key) => {
const getSnapshot = useMemo(() => {
return () => {
return reactiveIndex.getPksByKey(key);
};
}, [key, reactiveIndex]);
const subscribe = useMemo(() => {
return (onStoreChange) => {
reactiveIndex.updateEventEmitter.subscribeOnKey(key, onStoreChange);
return () => {
reactiveIndex.updateEventEmitter.unsubscribeFromKey(
key,
onStoreChange
);
};
};
}, [key, reactiveIndex.updateEventEmitter]);
const snapshot = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
return snapshot;
};
var useSelectPksByIndexKeysArrayBased = (reactiveIndex, keys) => {
const prevKeysRef = useRef();
const keysAreEqual = arraysEqual(prevKeysRef.current || EMPTY_ARRAY, keys);
if (!keysAreEqual) {
prevKeysRef.current = keys;
}
const snapshotValueRef = useRef();
const subscribe = useMemo(() => {
snapshotValueRef.current = keys.map((key) => reactiveIndex.getPksByKey(key)).flat();
return (onStoreChange) => {
const prevKeys = prevKeysRef.current;
if (!prevKeys) {
return () => {
};
}
const updateSnapshot = () => {
snapshotValueRef.current = keys.map((key) => reactiveIndex.getPksByKey(key)).flat();
onStoreChange();
};
reactiveIndex.updateEventEmitter.subscribeOnKeys(
prevKeys,
updateSnapshot
);
return () => {
reactiveIndex.updateEventEmitter.unsubscribeFromKeys(
prevKeys,
updateSnapshot
);
};
};
}, [prevKeysRef.current, reactiveIndex.updateEventEmitter]);
const getSnapshot = useMemo(() => {
return () => {
return snapshotValueRef.current;
};
}, []);
const snapshot = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
return snapshot;
};
var useSelectPksByIndexKeyArrayBased = (reactiveIndex, key) => {
const prevKeyRef = useRef();
const keyAreEqual = prevKeyRef.current === key;
if (!keyAreEqual) {
prevKeyRef.current = key;
}
const snapshotValueRef = useRef();
const subscribe = useMemo(() => {
snapshotValueRef.current = reactiveIndex.getPksByKey(key);
return (onStoreChange) => {
const prevKey = prevKeyRef.current;
if (!prevKey) {
return () => {
};
}
const updateSnapshot = () => {
snapshotValueRef.current = reactiveIndex.getPksByKey(prevKey);
onStoreChange();
};
reactiveIndex.updateEventEmitter.subscribeOnKey(
prevKey,
updateSnapshot
);
return () => {
reactiveIndex.updateEventEmitter.unsubscribeFromKey(
prevKey,
updateSnapshot
);
};
};
}, [key, reactiveIndex.updateEventEmitter]);
const getSnapshot = useMemo(() => {
return () => {
return snapshotValueRef.current;
};
}, []);
const snapshot = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
return snapshot;
};
var useSelectEntityByPk = (reactiveCollection, pk) => {
const getSnapshot = useMemo(
() => () => reactiveCollection.getOneByPk(pk),
[pk, reactiveCollection]
);
const subscribe = useMemo(() => {
return (onStoreChange) => {
reactiveCollection.updateEventEmitter.subscribeOnKey(
pk,
onStoreChange
);
return () => {
reactiveCollection.updateEventEmitter.unsubscribeFromKey(
pk,
onStoreChange
);
};
};
}, [pk, reactiveCollection.updateEventEmitter]);
const snapshot = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
return snapshot;
};
function arraysEqual(a, b) {
if (a === b) return true;
if (a.length !== b.length) return false;
for (let i = 0; i < a.length; i++) {
if (a[i] !== b[i]) return false;
}
return true;
}
var useSelectEntitiesByPks = (reactiveCollection, pks) => {
const prevPksRef = useRef();
const pksAreEqual = arraysEqual(prevPksRef.current || EMPTY_ARRAY, pks);
if (!pksAreEqual) {
prevPksRef.current = pks;
}
const snapshotRef = useRef();
const subscribe = useMemo(() => {
snapshotRef.current = pks.map((pk) => reactiveCollection.getOneByPk(pk));
return (onStoreChange) => {
const prevPks = prevPksRef.current;
if (!prevPks) {
return () => {
};
}
const updateSnapshot = () => {
snapshotRef.current = prevPks.map(
(pk) => reactiveCollection.getOneByPk(pk)
);
onStoreChange();
};
reactiveCollection.updateEventEmitter.subscribeOnKeys(
prevPks,
updateSnapshot
);
return () => {
reactiveCollection.updateEventEmitter.unsubscribeFromKeys(
prevPks,
updateSnapshot
);
};
};
}, [prevPksRef.current, reactiveCollection.updateEventEmitter]);
const getSnapshot = useMemo(() => {
return () => {
return snapshotRef.current;
};
}, []);
const snapshot = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
return snapshot;
};
var useSelectEntitiesByIndexKeySetBased = (reactiveCollection, reactiveIndex, key) => {
const pks = useSelectPksByIndexKeySetBased(reactiveIndex, key);
const pksArray = useMemo(
() => pks ? Array.from(pks) : EMPTY_ARRAY,
[pks]
);
return useSelectEntitiesByPks(reactiveCollection, pksArray);
};
var useSelectEntitiesByIndexKeysSetBased = (reactiveCollection, reactiveIndex, keys) => {
const pks = useSelectPksByIndexKeysSetBased(reactiveIndex, keys);
const pksArray = useMemo(
() => pks ? Array.from(pks) : EMPTY_ARRAY,
[pks]
);
return useSelectEntitiesByPks(reactiveCollection, pksArray);
};
var useSelectEntitiesByIndexKeyArrayBased = (reactiveCollection, reactiveIndex, key) => {
const pks = useSelectPksByIndexKeyArrayBased(reactiveIndex, key);
return useSelectEntitiesByPks(
reactiveCollection,
pks || EMPTY_ARRAY
);
};
var useSelectEntitiesByIndexKeysArrayBased = (reactiveCollection, reactiveIndex, keys) => {
const pks = useSelectPksByIndexKeysArrayBased(reactiveIndex, keys) || EMPTY_ARRAY;
return useSelectEntitiesByPks(reactiveCollection, pks);
};
// src/context/index.tsx
import { createContext, useContext } from "react";
import { jsx } from "react/jsx-runtime";
var OIMRICollectionsContext = createContext(
{}
);
function createOIMCollectionsContext() {
return createContext({});
}
function OIMRICollectionsProvider({ collections, children, context }) {
const ContextToUse = context || OIMRICollectionsContext;
return /* @__PURE__ */ jsx(ContextToUse.Provider, { value: collections, children });
}
function useOIMCollectionsContext(context) {
const contextToUse = context || OIMRICollectionsContext;
const collections = useContext(contextToUse);
if (!collections || Object.keys(collections).length === 0) {
throw new Error(
"useOIMCollectionsContext must be used within an OIMRICollectionsProvider"
);
}
return collections;
}
export {
OIMRICollectionsContext,
OIMRICollectionsProvider,
createOIMCollectionsContext,
useOIMCollectionsContext,
useSelectEntitiesByIndexKeyArrayBased,
useSelectEntitiesByIndexKeySetBased,
useSelectEntitiesByIndexKeysArrayBased,
useSelectEntitiesByIndexKeysSetBased,
useSelectEntitiesByPks,
useSelectEntityByPk,
useSelectPksByIndexKeyArrayBased,
useSelectPksByIndexKeySetBased,
useSelectPksByIndexKeysArrayBased,
useSelectPksByIndexKeysSetBased
};