react-firehooks
Version:
Lightweight dependency-free collection of React hooks for Firebase
53 lines (52 loc) • 2.31 kB
JavaScript
import { useEffect, useMemo, useRef } from "react";
import { useIsMounted } from "./useIsMounted.js";
import { useMultiLoadingValue } from "./useMultiLoadingValue.js";
/**
* @internal
*/
export function useMultiGet(references, getData, isEqual) {
const isMounted = useIsMounted();
const { states, setError, setLoading, setValue } = useMultiLoadingValue(references.length);
const prevReferences = useRef([]);
const ongoingFetchReferences = useRef([]);
useEffect(() => {
// shorten `prevReferences` size if number of references was reduced
prevReferences.current = prevReferences.current.slice(0, references.length);
// shorten `ongoingFetchReferences` size if number of references was reduced
ongoingFetchReferences.current = ongoingFetchReferences.current.slice(0, references.length);
// fetch to new references
const changedReferences = references
.map((ref, refIndex) => [ref, refIndex])
.filter(([ref, refIndex]) => !isEqual(ref, prevReferences.current[refIndex]));
for (const [ref, refIndex] of changedReferences) {
prevReferences.current[refIndex] = ref;
setLoading(refIndex);
ongoingFetchReferences.current[refIndex] = ref;
(async () => {
try {
const data = await getData(ref);
if (!isMounted.current) {
return;
}
if (!isEqual(ongoingFetchReferences.current[refIndex], ref)) {
return;
}
setValue(refIndex, data);
}
catch (e) {
if (!isMounted.current) {
return;
}
if (!isEqual(ongoingFetchReferences.current[refIndex], ref)) {
return;
}
// We assume this is always a Error
setError(refIndex, e);
}
})();
}
// TODO: double check dependencies
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [references]);
return useMemo(() => states.map((state) => [state.value, state.loading, state.error]), [states]);
}