You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Firestore更新操作错误覆盖用户数据问题求助

Firestore更新操作偶发用户数据错误覆盖问题

问题详情

  • 使用Firebase Authentication的signInWithEmailAndPassword完成身份验证
  • 用户数据以唯一ID为标识存储在Firestore中
  • 后台仪表盘支持展示所有用户并提供编辑功能
  • 核心异常:编辑某用户数据时,偶尔会错误覆盖另一用户的Firestore文档,导致数据丢失

示例场景

用户A(ID dv6d...)和用户B(ID pzF1...),编辑用户B的数据时,有时会意外覆盖用户A的文档,造成用户A的数据丢失。

相关代码

展示所有用户的组件代码

function User() {
  const { deleteData, getData } = useAdmin();
  const [userData, setUserData] = useState([]);
  const [page, setPage] = useState(1);
  const [selectedUser, setSelectedUser] = useState(null);
  const [isModalOpen, setIsModalOpen] = useState(false);
  const resultsPerPage = 10;

  const handleSelectedUser = (user) => {
    setSelectedUser(user);
    setIsModalOpen(true);
  };

  useEffect(() => {
    const loadUserData = async () => {
      await getData("Users", setUserData);
    };
    loadUserData();
  }, []);

  return (
    <>
      <TableContainer>
        <Table>
          <TableHeader>
            <tr>
              <TableCell>Full Name</TableCell>
              <TableCell>Email</TableCell>
              //similar other entries
            </tr>
          </TableHeader>
          <TableBody>
            {userData.slice((page - 1) * resultsPerPage, page * resultsPerPage).map((user, i) => (
              <TableRow key={i}>
                <TableCell>{user?.fullName}</TableCell>
                <TableCell>{user?.email}</TableCell>              
                <TableCell>
                  <Button onClick={() => handleSelectedUser(user)}>Edit</Button>
                </TableCell>
              </TableRow>
            ))}
          </TableBody>
        </Table>
      </TableContainer>

      {selectedUser && (
        <EditUser
          user={selectedUser}
          isModalOpen={isModalOpen}
          closeModal={() => setIsModalOpen(false)}
        />
      )}
    </>
  );
}

编辑用户组件代码

export const EditUser = ({ user, isModalOpen, closeModal }) => {
  const [updatedData, setUpdatedData] = useState({ ...user });
  const { updateData } = useAdmin();

  const handleSave = async () => {
    await updateData(user?.id, "Users", updatedData, setLoading);
    closeModal();
  };

  const handleChange = (e) => {
    setUpdatedData({ ...updatedData, [e.target.name]: e.target.value });
  };

  return (
    <Modal isOpen={isModalOpen} onClose={closeModal}>
      <ModalHeader>Edit User</ModalHeader>
      <ModalBody>
        <Input
          name="fullName"
          defaultValue={user?.fullName}
          onChange={handleChange}
        />
        <Input
          name="email"
          defaultValue={user?.email}
          onChange={handleChange}
        />
       
      </ModalBody>
      <ModalFooter>
        <Button onClick={handleSave}>Save</Button>
      </ModalFooter>
    </Modal>
  );
};

AdminContext状态管理代码

// removed necessary imports for better readability 
const AdminContext = createContext();

export const useAdmin = () => useContext(AdminContext);

export const AdminProvider = ({ children }) => {
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);

  const updateData = async (docId, dbName, updatedData, setLoading) => {
    try {
      setLoading(true);
      const docRef = doc(db, dbName, docId);

      await runTransaction(db, async (transaction) => {
        const docSnapshot = await transaction.get(docRef);

        if (!docSnapshot.exists()) {
          throw new Error("Document does not exist!");
        }

        const { id, ...dataWithoutId } = updatedData;

        // Perform the update within the transaction
        transaction.update(docRef, dataWithoutId);
      });

      toastSuccess(`${dbName} Updated Successfully`);
    } catch (error) {
      toastError(error.message);
      setError(error.message);
    } finally {
      setLoading(false);
    }
  };

  const getData = useCallback(async (dbName, setloading, setData) => {
    setloading(true);
    try {
      const data = [];
      const querySnapshot = await getDocs(collection(db, dbName));
      querySnapshot.forEach((doc) => {
        data.push({ id: doc.id, ...doc.data() });
      });
      setData(data);
      setloading(false);
    } catch (error) {
      toastError(error.message);
      setError(error.message);
      setloading(false);
    }
  }, []);

const value = {
      updateData,
      getData
    };

  return (
    <AdminContext.Provider value={value}>
      {children}
    </AdminContext.Provider>
  );
};

内容的提问来源于stack exchange,提问作者Shailendra Singh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 14:40:05