首页 > 解决方案 > 如何使用反应条件更新useState-hook?

问题描述

我正在使用带有 firebase 的反应钩子(useEffect 和 useState)。

我有一组用户,可以毫无问题地从 firebase 获取。简化的代码如下所示:

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();
    };
  }, []);

到目前为止,一切都很好。

如果我现在更改用户的某些属性,firebase 会触发并触发 useEffect-hook(这就是我想要的)。

这里的问题:通过这个触发我的用户数组(useState)得到更新并再次推送相同的用户。

我现在想要实现的目标如下:

我只希望每个用户在我的用户数组中一次。所以只有新用户应该被添加到这个数组中。我想我需要在 setUsers 方法中进行条件检查。

我想过这样的事情:

  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]
          }
        );

正如代码中的评论所述:如何将我的用户更新/设置为较新的版本(以防插入新用户)或让用户保持原样(无需再次添加)?

我很感谢任何建议!

标签: javascriptreactjsreact-hooksarrow-functions

解决方案


避免间接地(使用Array.push或任何其他方式)改变状态,这是不一致的。如果没有变化,则返回原始状态,如果有,则返回一个新对象。例如:

setUsers(oldUsers => {
  if (oldUsers.find(user => user.id === currentUser.id)) 
    return oldUsers;
  return [...oldUsers, currentUser];
});

setUsers在这种特殊情况下,如果没有更改,您可能希望完全避免调用,因为状态本身是可用的(并且您可以在之前检查用户的存在)。


作为旁注,indexOf在这种情况下检查将不起作用,因为您创建了一个新对象(根据您在快照中获得的数据)。这就是为什么在我的示例中它是基于谓词的查找。


推荐阅读