I'm pretty new to both React and Firebase, and maybe that's why I'm struggling with this issue.
I am trying to retrieve data from a Cloud Firestore collection and simply display it in a react MUI table.
Since I want to keep the table always up to date in case of any change (delete, add, update) in the collection, I thought of using the onSnapshot function that should provide me with whatever changes happen, when it happens.
So I wrote a code that looks like this:
const [rows, setRows] = useState([]);
useEffect(() => {
const ref = collection(firebaseDB, 'my-collection');
const unsubscribe = onSnapshot(ref, (querySnapshot) => {
querySnapshot.docs.forEach((doc) => setRows((prev) => [...prev, doc.data()]));
});
return () => unsubscribe();
}, []);
rows is an array of objects that will be used to show all the records in my table.
This code works when I first load the page, it shows me all the records (documents) present in the collection. But when I add a new document to the collection (after onClick event on a Modal), instead of just adding the new doc to the rows array, it duplicates the existing elements and then appends the new one.
If I refresh the page I see the list clean as it should be and no duplicates are shown.
What am I missing here?
CodePudding user response:
You are missing the fact that onShanpshot will bring all the data of the collection (query) on any change. So you are getting all the data, setting this data to state, then on any update - onSnapshot is triggered and you are getting ALL the records, and you are appending all those records to your array by setRows((prev) => [...prev, doc.data()])
instead of re-setting this array completely.
And please, do not setState inside of the loops, not really efficient and a big chance to get some bugs. Prepare all the data first and set state once in the very end.
const newRows = querySnapshot.docs.map((doc) => doc.data());
setRows(newRows);