UNPKG

@oimdb/react

Version:

React integration for OIMDB - Hooks for selection and subscription with external storage

280 lines (278 loc) 8.88 kB
// 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 };