I have built a custom hook:
const useFirestoreCollection = async (collectionName) => { const [documents, setDocuments] = useState([]); useEffect(() => { const fetchData = async () => { const querySnapshot = await getDocs(collection(db, collectionName)); const documentsData = []; querySnapshot.forEach((doc) => { documentsData.push({ id: doc.id, ...doc.data(), }); }); setDocuments(documentsData); }; fetchData(); }, []); return documents; };
I can use it in my component like this:
const [myData, setMyData] = useState([]); useFirestoreCollection('registeredUsers') .then((data) => { setMyData(data); // Data Access }) .catch((error) => { console.log(error); // Error });
I can also remove the async in the custom hook:
const useFirestoreCollection = (collectionName) => { <- ASYNC DELETED const [documents, setDocuments] = useState([]); useEffect(() => { const fetchData = async () => { const querySnapshot = await getDocs(collection(db, collectionName)); const documentsData = []; querySnapshot.forEach((doc) => { documentsData.push({ id: doc.id, ...doc.data(), }); }); setDocuments(documentsData); }; fetchData(); }, []); return documents; };
...and use it in my component like this:
const myData = useFirestoreCollection('registeredUsers')
I tried to figure out the best way but couldn't.
When should you use the async keyword in hooks, and when shouldn't you use it?
I've never seen a situation where a hook should be async. The hook now returns a promise instead of just the state and setState functions you want the component to use. This would be a major anti-pattern and make the simplicity of the hook very complicated.
If you need to use async/await functionality in a hook, you can declare an async function in it. Just like you do.
The second method is obviously the correct way to do this.
In the first case, making the hook async is useless because there is nothing asynchronous in the hook, only inside the
useEffect
.This makes it harder to use and makes you duplicate state.