This useEffect is rendering one time if dependency array is empty but multiple times if i put folderRef in dependency array. I want to render the component only when I add or delete some folder. Please Help
import React, { useState, useEffect , useRef } from "react";
import { db } from "../firebase";
import { collection, getDocs } from "firebase/firestore";
import FolderData from "./FolderData";
function ShowFolder(props) {
const [folders, setFolders] = useState([]);
const folderRef = useRef(collection(db, "folders"));
useEffect(() => {
const getData = async () => {
const data = await getDocs(folderRef.current);
const folderData = data.docs.map((doc) => {
return { id: doc.id, data: doc.data() };
});
console.log(folderData);
setFolders(folderData);
};
getData();
}, [folderRef]);
return (
<div className="container md:px-4 mx-auto py-10">
<div className="md:grid lg:grid-cols-6 md:grid-cols-3 mlg:grid-cols-3 md:gap-10 space-y-6 md:space-y-0 px-1 md:px-0 mx-auto">
{folders.map((folder) => {
return (
<div key={folder.id}>
{folder.data.userId === props.userId && (
<div>
<FolderData key={folder.id} folder={folder} />
</div>
)}
</div>
);
})}
</div>
</div>
);
}
export default ShowFolder;
You redeclare folderRef
each render cycle, so if you include it in the useEffect
hook's dependency array it will trigger render looping.
If you don't refer to folderRef
anywhere else in the component then move it into the useEffect
hook callback to remove it as an external dependnecy.
const [folders, setFolders] = useState([]);
useEffect(() => {
const folderRef = collection(db, "folders");
const getData = async () => {
const data = await getDocs(folderRef);
const folderData = data.docs.map((doc) => {
return { id: doc.id, data: doc.data() };
});
console.log(folderData);
setFolders(folderData);
};
getData();
}, []);
Or store it in a React ref so it can be safely referred to as a stable reference.
const [folders, setFolders] = useState([]);
const folderRef = useRef(collection(db, "folders"));
useEffect(() => {
const getData = async () => {
const data = await getDocs(folderRef.current);
const folderData = data.docs.map((doc) => {
return { id: doc.id, data: doc.data() };
});
console.log(folderData);
setFolders(folderData);
};
getData();
}, [folderRef]);
I've gathered that you are updating the folders
collection elsewhere in your app and want this component to "listen" for these changes. For this you can implement an onSnapshot
listener.
It may look similar to the following:
const [folders, setFolders] = useState([]);
useEffect(() => {
const unsubscribe = onSnapshot(
collection(db, "folders"),
(snapshot) => {
const folderData = [];
snapshot.forEach((doc) => {
folderData.push({
id: doc.id,
data: doc.data(),
});
});
setFolders(folderData);
},
);
// Return cleanup function to stop listening to changes
// on component unmount
return unsubscribe;
}, []);