Reputation: 29
I'm using react hooks (useEffect and useState) with firebase.
I have a collection of users which can be getted from firebase without any problems. The simplified code looks like this:
const [users, setUsers] = useState([]);
useEffect(() => {
const unsubscribe = database.collection("users").onSnapshot((snapshot) => {
snapshot.forEach((doc) => {
const currentUser = {
id: doc.id,
...doc.data(),
};
setUsers((oldUsers) => [...oldUsers, currentUser]);
});
});
return () => {
unsubscribe();
};
}, []);
So far, so good.
If I change some properties of a user now, firebase fires and the useEffect-hook is triggered (thats what I want).
The problem here: through this firing my users array (useState) gets updated and gets pushed the same users again.
What I want to achieve now is the following:
I only want each user once in my users array. So that only new users should be added to this array. I think I need a conditional check in the setUsers-method.
I thought about something like this:
setUsers(
(oldUsers) =>
{
if (oldUsers.indexOf(currentUser) === -1) {
oldUsers.push(currentUser);
}
// HERE I'M NOT SURE WHAT TO DO
// how can I set my users to the updated oldUsers?
// I made some first steps with those approaches...
1) return oldUsers;
2) setUsers(oldUsers);
3) [...oldUsers]
}
);
As mentioned in comments in the code: how can I update/set my users to a newer version (in case if a new user is inserted) or just let the users as they are (without adding them again)?
I'm thankful for any advice!
Upvotes: 2
Views: 2340
Reputation: 106385
Avoid mutating the state indirectly (with Array.push
or any other way), it's not consistent. Instead return the original state if there's no change, and a new object if there's one. For example:
setUsers(oldUsers => {
if (oldUsers.find(user => user.id === currentUser.id))
return oldUsers;
return [...oldUsers, currentUser];
});
In this particular case you might want to avoid calling setUsers
altogether if there's no change, as state itself is available (and you can check user's presence before).
As a sidenote, indexOf
check won't work in this case, as you create a new object (from the data you've got in a snapshot). That's why it's predicate-based find in my example.
Upvotes: 1