From 7baa3cd7a85002518a3da3993beacdf5ad2f5a80 Mon Sep 17 00:00:00 2001 From: hiroro-work Date: Thu, 27 Jun 2024 14:18:45 +0900 Subject: [PATCH 1/3] refactor --- README.md | 1 + src/firestore/useCollectionData.ts | 12 ++++++++---- src/firestore/useDocumentData.ts | 15 ++++++++++----- src/storage/useStorageUrl.ts | 27 ++++++--------------------- src/utils/index.ts | 1 + src/utils/useAsync.ts | 30 ++++++++++++++++++++++++++++++ 6 files changed, 56 insertions(+), 30 deletions(-) create mode 100644 src/utils/useAsync.ts diff --git a/README.md b/README.md index 7701bce..c90c71b 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,7 @@ pnpm add @sonicgarden/react-fire-hooks ## Utility +- [useAsync](https://github.com/SonicGarden/react-fire-hooks/blob/main/src/utils/useAsync.ts) - [useCustomCompareEffect](https://github.com/SonicGarden/react-fire-hooks/blob/main/src/utils/useCustomCompareEffect.ts) - [useDeepCompareEffect](https://github.com/SonicGarden/react-fire-hooks/blob/main/src/utils/useDeepCompareEffect.ts) diff --git a/src/firestore/useCollectionData.ts b/src/firestore/useCollectionData.ts index 726e9e4..408473b 100644 --- a/src/firestore/useCollectionData.ts +++ b/src/firestore/useCollectionData.ts @@ -10,20 +10,24 @@ export const useCollectionData = (query?: Query | null) => { useQueriesEffect(() => { if (!query) return; + let mounted = true; setLoading(true); const unsubscribe = onSnapshot( query, (snapshot) => { - setData(snapshot.docs.map((doc) => doc.data())); - setLoading(false); + mounted && setData(snapshot.docs.map((doc) => doc.data())); + mounted && setLoading(false); }, (error) => { - setLoading(false); + mounted && setLoading(false); throw error; }, ); - return () => unsubscribe(); + return () => { + unsubscribe(); + mounted = false; + }; // NOTE: Since a warning is displayed when the query is null, an empty object is being passed. }, [query || ({} as Query)]); diff --git a/src/firestore/useDocumentData.ts b/src/firestore/useDocumentData.ts index 92f3b82..69cf4b9 100644 --- a/src/firestore/useDocumentData.ts +++ b/src/firestore/useDocumentData.ts @@ -8,8 +8,10 @@ export const useDocumentData = (ref?: DocumentReference | null) => { const [loading, setLoading] = useState(); useRefsEffect(() => { + let mounted = true; + if (!ref) { - setData(undefined); + mounted && setData(undefined); return; } @@ -17,16 +19,19 @@ export const useDocumentData = (ref?: DocumentReference | null) => { const unsubscribe = onSnapshot( ref, (snapshot) => { - setData(snapshot.data()); - setLoading(false); + mounted && setData(snapshot.data()); + mounted && setLoading(false); }, (error) => { - setLoading(false); + mounted && setLoading(false); throw error; }, ); - return () => unsubscribe(); + return () => { + unsubscribe(); + mounted = false; + }; // NOTE: Since a warning is displayed when the ref is null, an empty object is being passed. }, [ref || ({} as DocumentReference)]); diff --git a/src/storage/useStorageUrl.ts b/src/storage/useStorageUrl.ts index f137878..ef1bfc5 100644 --- a/src/storage/useStorageUrl.ts +++ b/src/storage/useStorageUrl.ts @@ -1,30 +1,15 @@ import { getBlob, getStorage, ref } from 'firebase/storage'; -import { useEffect, useMemo, useState } from 'react'; +import { useAsync } from '../utils/index.js'; export const useStorageUrl = (path?: string | null) => { - const [loading, setLoading] = useState(false); - const [url, setUrl] = useState(null); - const [error, setError] = useState(null); - - useEffect(() => { + const { loading, data, error } = useAsync(async () => { if (!path) { - setUrl(null); - setError(null); - return; + return { url: null, blob: null }; } - setLoading(true); - getBlob(ref(getStorage(), path)) - .then((blob) => { - setUrl(URL.createObjectURL(blob)); - }) - .catch((error) => { - setError(error); - }) - .finally(() => { - setLoading(false); - }); + const blob = await getBlob(ref(getStorage(), path)); + return { url: URL.createObjectURL(blob), blob }; }, [path]); - return useMemo(() => ({ loading, url, error }), [loading, url, error]); + return { loading, data, error }; }; diff --git a/src/utils/index.ts b/src/utils/index.ts index 65829e2..4aa4074 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -1,2 +1,3 @@ +export * from './useAsync.js'; export * from './useCustomCompareEffect.js'; export * from './useDeepCompareEffect.js'; diff --git a/src/utils/useAsync.ts b/src/utils/useAsync.ts new file mode 100644 index 0000000..b5faae6 --- /dev/null +++ b/src/utils/useAsync.ts @@ -0,0 +1,30 @@ +import { useState, useEffect } from 'react'; +import type { DependencyList } from 'react'; + +export const useAsync = (fn: () => T | Promise, deps: DependencyList = []) => { + const [loading, setLoading] = useState(false); + const [data, setData] = useState(null); + const [error, setError] = useState(null); + + useEffect(() => { + let mounted = true; + + setLoading(true); + try { + (async () => { + const _data = await fn(); + mounted && setData(_data); + })(); + } catch (error) { + mounted && setError(error); + } finally { + mounted && setLoading(false); + } + + return () => { + mounted = false; + }; + }, deps); + + return { loading, data, error }; +}; From ea203b0d6d29b073477533f9e1f15401418e9230 Mon Sep 17 00:00:00 2001 From: hiroro-work Date: Thu, 27 Jun 2024 14:27:07 +0900 Subject: [PATCH 2/3] fix a bit --- src/storage/useStorageUrl.ts | 2 +- src/utils/useAsync.ts | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/storage/useStorageUrl.ts b/src/storage/useStorageUrl.ts index ef1bfc5..eb5a561 100644 --- a/src/storage/useStorageUrl.ts +++ b/src/storage/useStorageUrl.ts @@ -4,7 +4,7 @@ import { useAsync } from '../utils/index.js'; export const useStorageUrl = (path?: string | null) => { const { loading, data, error } = useAsync(async () => { if (!path) { - return { url: null, blob: null }; + return null; } const blob = await getBlob(ref(getStorage(), path)); diff --git a/src/utils/useAsync.ts b/src/utils/useAsync.ts index b5faae6..7281171 100644 --- a/src/utils/useAsync.ts +++ b/src/utils/useAsync.ts @@ -2,14 +2,13 @@ import { useState, useEffect } from 'react'; import type { DependencyList } from 'react'; export const useAsync = (fn: () => T | Promise, deps: DependencyList = []) => { - const [loading, setLoading] = useState(false); + const [loading, setLoading] = useState(true); const [data, setData] = useState(null); const [error, setError] = useState(null); useEffect(() => { let mounted = true; - setLoading(true); try { (async () => { const _data = await fn(); From 6f61b6a808861478cf53e5ae3efc5420b5bf8966 Mon Sep 17 00:00:00 2001 From: hiroro-work Date: Tue, 23 Jul 2024 06:32:06 +0900 Subject: [PATCH 3/3] refactor --- src/firestore/useDocumentsData.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/firestore/useDocumentsData.ts b/src/firestore/useDocumentsData.ts index f415e86..a45c61a 100644 --- a/src/firestore/useDocumentsData.ts +++ b/src/firestore/useDocumentsData.ts @@ -30,7 +30,6 @@ export const useDocumentsData = (refs?: DocumentReference[] | null) => { resolve(); }, (error) => { - if (isMounted) setLoading(false); throw error; }, ); @@ -38,8 +37,8 @@ export const useDocumentsData = (refs?: DocumentReference[] | null) => { }); }); - Promise.all(fetchDataPromises).then(() => { - setLoading(false); + Promise.all(fetchDataPromises).finally(() => { + if (isMounted) setLoading(false); }); return () => {