firebase - 使用 firestore 数据进行 React hooks - 30 秒内读取 1.1k 次(来自包含 3 个文档和 2 个属性的 2 个集合)

标签 firebase google-cloud-firestore react-hooks

我试图了解 Cloud Firestore 读取配额的工作原理。我已阅读this post以及对此的回应。我的控制台是打开的,但我无法解释包含 3 个文档(每个文档有 2 个属性)的单个集合如何构成一个“繁忙的控制台”。

我正在努力理解文档。

我在 firestore 中有两个集合。每一项有 3 个文档。每个文档有 2 个属性。我使用这些属性来填充 Material UI 中“自动完成”选择菜单中的选项。

在本地主机中,我一直在运行表单来测试使用单个快照将这些属性放入自动完成选择菜单中。在 30 秒内,这两个表单项在 firestore 中产生了 1.1k 次读取。

我想:

  1. snapshot仅当 firestore 中的数据发生更改时更新。

  2. 通过使用取消订阅, Hook 将停止监听 firestore 中的更改。

  3. 通过将列表状态添加为 Hook 的依赖项(useEffect block 末尾的 orgList),提高了 firestore 读取的效率: https://medium.com/javascript-in-plain-english/firebase-firestore-database-realtime-updates-with-react-hooks-useeffect-346c1e154219 .

任何人都可以看到仅使用 2 个输入项运行此表单如何生成 1.1k 读取(目前整个应用程序中没有其他 firestore 调用)。

import React, { useState, useEffect } from 'react';
import Checkbox from '@material-ui/core/Checkbox';
import TextField from '@material-ui/core/TextField';
import Autocomplete from '@material-ui/lab/Autocomplete';
import CheckBoxOutlineBlankIcon from '@material-ui/icons/CheckBoxOutlineBlank';
import CheckBoxIcon from '@material-ui/icons/CheckBox';
import firebase from "../../../../../firebase";

const icon = <CheckBoxOutlineBlankIcon fontSize="small" />;
const checkedIcon = <CheckBoxIcon fontSize="small" />;

export default function CheckboxesTags() {
  const [orgList, setOrgList] = useState([]);
  const [selectedOrgList, setSelectedOrgList] = useState();
  const [loading, setLoading ] = useState(true);
  const [ error, setError ] = useState(false);

  useEffect(() => {
    // if (doc.exists) {
      const unsubscribe = firebase
        .firestore()
        .collection("organisations")
        .onSnapshot((snapshot) => {
          const orgList = snapshot.docs.map((doc) => ({
            id: doc.id,
            shortName: doc.data().shortName,
            location: doc.data().location
          }));
          setOrgList(orgList);
          console.log("orglist", orgList)
        }, () => {
          setError(true)
        });
        setLoading(false);
        return() => unsubscribe();
     
    
  }, [orgList]);


   

  return (
      <div>
      
        <Autocomplete
        multiple
        id="orgList options"
        options={orgList}
        disableCloseOnSelect
        getOptionLabel={(option) => option.shortName}
        renderOption={(orgList, { selected }) => (
            <React.Fragment>
            <Checkbox
                icon={icon}
                checkedIcon={checkedIcon}
                style={{ marginRight: 8 }}
                checked={selected}
            />
            {orgList.shortName}  <span style={{marginRight: "4px", marginLeft: "4px"}}>-</span>
            {orgList.location}
            </React.Fragment>
        )}
        style={{ width: 500 }}
        renderInput={(params) => (
            <TextField {...params} 
            variant="outlined" 
            label="Select Organisation" 
            placeholder="Acme Inc." 
          />
        )}
        />
    </div>
  );
}

另一种形式与此完全相同,但它没有 orgList - 它有 userList。否则 - 都是一样的(因此:2 个集合,每个集合中有 3 个文档,每个文档中有 2 个属性)。

最佳答案

  const [orgList, setOrgList] = useState([]);
  const [selectedOrgList, setSelectedOrgList] = useState();
  const [loading, setLoading ] = useState(true);
  const [ error, setError ] = useState(false);

  useEffect(() => {
    // if (doc.exists) {
      const unsubscribe = firebase
        .firestore()
        .collection("organisations")
        .onSnapshot((snapshot) => {
          const orgList = snapshot.docs.map((doc) => ({
            id: doc.id,
            shortName: doc.data().shortName,
            location: doc.data().location
          }));
          setOrgList(orgList);
          console.log("orglist", orgList)
        }, () => {
          setError(true)
        });
        setLoading(false);
        return() => unsubscribe();
     
    
  }, [orgList]);

根据我对此的理解,我们告诉 React,如果 orgList 发生变化,则运行此效果。该效果执行以下操作:

  1. 调用 Firestore。
  2. Map...<- 这会导致问题,因为我们正在创建一个新数组。
  3. setOrgList(orgList) <- 这就是问题所在

现在 orgList 已更改,React 必须重新运行效果。我创建了一个类似的 stackblitz(来自 Material-ui 的主页),它可能会导致此问题。请参阅https://stackblitz.com/edit/evsxm2?file=demo.js 。查看控制台并注意它一直在运行。

解决这个问题的可能方法

如果我们只需要一次数据......

建议1:在useEffect开头加一个if条件

  const [orgList, setOrgList] = useState([]);
  const [selectedOrgList, setSelectedOrgList] = useState();
  const [loading, setLoading ] = useState(true);
  const [ error, setError ] = useState(false);

  useEffect(() => {
      if (orgList.length > 0) {
         return; // we already have data, so no need to run this again
      }

      const unsubscribe = firebase
        .firestore()
        .collection("organisations")
        .onSnapshot((snapshot) => {
          const orgList = snapshot.docs.map((doc) => ({
            id: doc.id,
            shortName: doc.data().shortName,
            location: doc.data().location
          }));
          setOrgList(orgList);
          console.log("orglist", orgList)
        }, () => {
          setError(true)
        });
        setLoading(false);
        return() => unsubscribe();
     
    
  }, [orgList]);

建议2如果我们真的需要监听实时变化......? (我没有测试过)

  const [orgList, setOrgList] = useState([]);
  const [selectedOrgList, setSelectedOrgList] = useState();
  const [loading, setLoading ] = useState(true);
  const [ error, setError ] = useState(false);

  useEffect(() => {
      const unsubscribe = firebase
        .firestore()
        .collection("organisations")
        .onSnapshot((snapshot) => {
          const orgList = snapshot.docs.map((doc) => ({
            id: doc.id,
            shortName: doc.data().shortName,
            location: doc.data().location
          }));
          setOrgList(orgList);
        }, () => {
          setError(true)
        });
        setLoading(false);
        return() => unsubscribe();
     
    
  }, []); // we don't depend on orgList because we always overwrite it whenever there's a snapshot change

关于firebase - 使用 firestore 数据进行 React hooks - 30 秒内读取 1.1k 次(来自包含 3 个文档和 2 个属性的 2 个集合),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63009673/

相关文章:

firebase - 仅针对已登录用户在Flutter中获取Firestore数据

javascript - 带有 Firebase 的 Algolia 的 TypeError [ERR_HTTP_INVALID_HEADER_VALUE]

javascript - 如何在 HTML 页面上使用 Hooks 渲染对 ID 的 react ?

javascript - react : useEffect vs useMemo vs useState

javascript - 在哪里放置代码以在 Vue.js 中设置 Firebase 身份验证状态持久性?

firebase - 如何使用 Firebase 存储移动文件?

android - 如何在特定时间后(例如 10 分钟后)更新 firebase 数据库中的值?

firebase - Firestore 如何保存日期?

javascript - React Hooks,渲染之间的 prop 值随机变化

javascript - 如何在 Angular Fire 中保存对象的属性而不删除其他属性?