UNPKG

@ryo-98/react-api-bridge

Version:
84 lines (83 loc) 3.29 kB
import { useEffect, useImperativeHandle, useLayoutEffect, useMemo, useRef } from "react"; import { getIsMulti, useFinalContextValue, getApiDesc, getResolverOrCreateWhenMissing } from "../../core/index.js"; import { useUniqueElementRef } from "../../utils/useUniqueElementRef.js"; import { useHookId } from "../../utils/useHookId.js"; import { tryInvoke } from "../../utils/tryInvoke.js"; import { appendToMappedSet } from "../../utils/mappedSet.js"; function useRegister(apiBridge, name, init, deps, hookOptions) { const isMulti = getIsMulti(name, apiBridge.bridgeOptions); const contextValue = useFinalContextValue(hookOptions, apiBridge.BridgeContext); const { apiNList } = useMemo(() => getApiDesc(name, contextValue.bridge, apiBridge.bridgeOptions), [name, contextValue]); const apiRef = useUniqueElementRef(apiNList); const hookId = useHookId(); const localApiRef = useRef(null); const isOwnerRef = useRef(false); const hasWarnedRef = useRef(false); useImperativeHandle(isMulti ? apiRef : localApiRef, () => { return init(); }, deps); useLayoutEffect(() => { if (isMulti) return; const entry = contextValue.bridge[name]; if (!entry) return; if (entry.ownerId === void 0 || entry.ownerId === hookId) { entry.ownerId = hookId; isOwnerRef.current = true; } else { isOwnerRef.current = false; if (!hasWarnedRef.current) { hasWarnedRef.current = true; console.warn( `[react-api-bridge] useRegister: the API "${String(name)}" is already registered by another component (only the first registered component can provide it in non-multi mode). The new registration is ignored to avoid overriding the existing API. If multiple registrations on the same field are intended, enable "isMulti: true" in the bridge options for this field.` ); } } return () => { if (isOwnerRef.current) { if (entry.ownerId === hookId) { entry.ownerId = void 0; } apiNList.current = null; isOwnerRef.current = false; } }; }, []); useLayoutEffect(() => { if (isMulti) return; if (isOwnerRef.current) { apiNList.current = localApiRef.current; } }); useEffect(() => { let clearFns = []; const { bucket } = getResolverOrCreateWhenMissing(apiNList, contextValue, true, apiBridge.pendingResolverMap); bucket.initialResolver?.resolve(apiNList); bucket.waiters.forEach((resolver) => { resolver.resolve(apiNList); }); bucket.waiters.clear(); const callbacks = apiBridge.cacheInitCbMap.get(apiNList); callbacks?.forEach((initInfo, hookId2) => { if (apiBridge.initializedOnInitMap.get(apiRef)?.has(hookId2)) return; initInfo.touchedRefs.add(apiRef); clearFns.push(appendToMappedSet(apiBridge.initializedOnInitMap, apiRef, hookId2)); const onInit = initInfo.onInit; if (isMulti) { const _assertedOnInit = onInit; clearFns.push(_assertedOnInit(apiRef, apiNList)); } else { const _assertedOnInit = onInit; clearFns.push(_assertedOnInit(apiRef)); } }); return () => { clearFns.forEach(tryInvoke); apiBridge.initializedOnInitMap.delete(apiRef); }; }, []); } export { useRegister };