@baqhub/sdk-react
Version:
The official React SDK for the BAQ federated app platform.
99 lines (98 loc) • 2.9 kB
JavaScript
import { AbortedError } from "@baqhub/sdk";
import isEqual from "lodash/isEqual.js";
import { useCallback, useEffect, useMemo, useRef, } from "react";
export function useConstant(builder) {
const valueRef = useRef(undefined);
if (!valueRef.current) {
valueRef.current = builder();
}
return valueRef.current;
}
export function useStable(value) {
const valueRef = useRef(value);
useEffect(() => {
valueRef.current = value;
}, [value]);
return useCallback((...args) => {
const currentValue = valueRef.current;
if (!currentValue) {
return;
}
currentValue(...args);
}, []);
}
export function useDeepMemo(memoFn, key) {
const value = useRef(undefined);
// eslint-disable-next-line react-hooks/exhaustive-deps
const result = value.current && isEqual(key, value.current.key)
? value.current
: { key, value: memoFn() };
useEffect(() => {
value.current = result;
}, [result]);
return result.value;
}
export function abortable(worker) {
const abort = new AbortController();
// Catch aborted errors.
async function effectAsync() {
try {
await null;
await Promise.resolve(worker(abort.signal));
}
catch (error) {
if (error instanceof AbortedError) {
return;
}
throw error;
}
}
effectAsync();
return () => {
abort.abort();
};
}
export function useAbortable(effect, deps) {
// eslint-disable-next-line react-hooks/exhaustive-deps
useEffect(() => abortable(effect), deps);
}
export function useUnmountSignal() {
const abortRef = useRef(undefined);
const abort = (() => {
const currentAbort = abortRef.current;
if (currentAbort && !currentAbort.signal.aborted) {
return currentAbort;
}
return new AbortController();
})();
useEffect(() => {
abortRef.current = abort;
return () => {
abort.abort();
};
}, [abort]);
return abort.signal;
}
export function useIsMounted() {
const isMountedRef = useRef(true);
useEffect(() => {
isMountedRef.current = true;
return () => {
isMountedRef.current = false;
};
}, []);
return { isMountedRef };
}
export function useImageUrl(blob) {
const imageUrl = useMemo(() => URL.createObjectURL(blob), [blob]);
useEffect(() => () => URL.revokeObjectURL(imageUrl), [imageUrl]);
return imageUrl;
}
export function useMergeWrap(firstWrapper, ...otherWrappers) {
return useMemo(() => {
return otherWrappers.reduce((acc, wrapper) => {
return children => acc(wrapper(children));
}, firstWrapper);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [firstWrapper, ...otherWrappers]);
}