【问题标题】:Reading firestore data via react hooks通过反应挂钩读取 Firestore 数据
【发布时间】:2020-11-28 22:49:12
【问题描述】:

我正在尝试弄清楚如何通过 react hooks 从 firestore 获取数据。

对于这次尝试,我尝试按照 blog post 中的示例进行操作。

我在 firestore 的一个名为“impact_metrics”的集合中创建了一个记录。

我试图弄清楚如何使用钩子在反应中显示它。

我的清单是:

import React, { useState, useEffect } from 'react';
import {Link } from 'react-router-dom';
import Typography from '@material-ui/core/Typography';
import ImpactMetricsForm from "./Form";
import firebase, { firestore } from "../../../firebase.js";
import { makeStyles } from '@material-ui/core/styles';
import clsx from 'clsx';
import ExpansionPanel from '@material-ui/core/ExpansionPanel';
import ExpansionPanelDetails from '@material-ui/core/ExpansionPanelDetails';
import ExpansionPanelSummary from '@material-ui/core/ExpansionPanelSummary';
import ExpansionPanelActions from '@material-ui/core/ExpansionPanelActions';
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
import Chip from '@material-ui/core/Chip';
import Button from '@material-ui/core/Button';
import Divider from '@material-ui/core/Divider';

const useStyles = makeStyles((theme) => ({
  root: {
    width: '100%',
  },
  heading: {
    fontSize: theme.typography.pxToRem(15),
  },
  secondaryHeading: {
    fontSize: theme.typography.pxToRem(15),
    color: theme.palette.text.secondary,
  },
  icon: {
    verticalAlign: 'bottom',
    height: 20,
    width: 20,
  },
  details: {
    alignItems: 'center',
  },
  column: {
    flexBasis: '33.33%',
  },
  helper: {
    borderLeft: `2px solid ${theme.palette.divider}`,
    padding: theme.spacing(1, 2),
  },
  link: {
    color: theme.palette.primary.main,
    textDecoration: 'none',
    '&:hover': {
      textDecoration: 'underline',
    },
  },
}));

const Title = {
    fontFamily: "'Montserrat', sans-serif",
    fontSize: "4vw",
    marginBottom: '2vh'
};

const Subhead = {
    fontFamily: "'Montserrat', sans-serif",
    fontSize: "calc(2vw + 1vh + .5vmin)",
    marginBottom: '2vh',
    marginTop: '8vh',
    width: "100%"
};

function useImpactMetrics() {
    const [impactMetrics, setImpactMetrics] = useState([])
    useEffect(() => {
      firebase
        .firestore()
        .collection("impact_metrics")
        .onSnapshot(snapshot => {
          const impactMetrics = snapshot.docs.map(doc => ({
            id: doc.id,
            ...doc.data(),
          }))
          setImpactMetrics(impactMetrics)
        })
    }, [])
    return impactMetrics
  }

const ImpactMetricsMenu = () => {

    const impactMetrics = useImpactMetrics()
    const classes = useStyles();

    return ( 
        <div style={{ marginLeft: "3vw"}}>
            <Typography variant="subtitle" className="blogParagraph" style={Subhead}>Select Metrics</Typography>
            
            
                
                    
                    
                       
            
            <div className={classes.root}>
            tet
            {impactMetrics.map(impactMetric => {
                return (
                <ExpansionPanel defaultExpanded>
                <ExpansionPanelSummary
                    expandIcon={<ExpandMoreIcon />}
                    aria-controls="panel1c-content"
                    id="panel1c-header"
                >
                    <div className={classes.column}>
                    <Typography className={classes.heading}>{impactMetric.title}</Typography>
                    </div>
                    <div className={classes.column}>
                    <Typography className={classes.secondaryHeading}>Select trip destination</Typography>
                    </div>
                </ExpansionPanelSummary>
                <ExpansionPanelDetails className={classes.details}>
                    <div className={classes.column} />
                    <div className={classes.column}>
                    <Chip label="Barbados" onDelete={() => {}} />
                    </div>
                    <div className={clsx(classes.column, classes.helper)}>
                    <Typography variant="caption">
                        Select your destination of choice
                        <br />
                        <a href="#secondary-heading-and-columns" className={classes.link}>
                        Learn more
                        </a>
                    </Typography>
                    </div>
                </ExpansionPanelDetails>
                <Divider />
                <ExpansionPanelActions>
                    <Button size="small">Cancel</Button>
                    <Button size="small" color="primary">
                    Save
                    </Button>
                </ExpansionPanelActions>
                </ExpansionPanel>

            )
        })}
            </div>
            sdf
        </div>   

     );
}
 
export default ImpactMetricsMenu;

当我尝试这个时,我在控制台中收到一条错误消息:

onSnapshot 中未捕获的错误:FirebaseError:缺失或不足 权限。

我的 Firestore 规则有:

// impact_metrics
    match /impact_metrics/{impactMetricId} {
      allow read;
      allow write;
    }

授予此权限还需要什么?

我想知道这是否可能与调用 firebase 的时间有关,所以我尝试按照this post 中的解决方案对 firestore 进行异步调用,如下所述。这是不正确的,但我不明白为什么。

function useImpactMetrics() {
    const [impactMetrics, setImpactMetrics] = useState([])
    useEffect(() => {
      const fetchImpactMetrics = async () => {
      firebase
        .firestore()
        .collection("impact_metrics")
        .onSnapshot(snapshot => {
          const impactMetrics = await snapshot.docs.map(doc => ({
            id: doc.id,
            ...doc.data(),
          }))
          setImpactMetrics(impactMetrics)
        })
    }, [fetchImpactMetrics])
    return impactMetrics
  }

下一次尝试

firestore 中有一条说明,规则系统在去年年底发生了变化。我尝试选择使用第二版并在规则中添加明确的列表权限。

我从通用入门工具包中了解到条件不是规则的强制性要求,但为了解决这个问题,我添加了它们。

新规则(包括将版本2添加到规则列表顶部)是:

 // impact_metrics
    match /impact_metrics/{impactMetricId} {
      allow read: if true;
      allow list: if true;
      allow write: if true;
    }

当我尝试这个时,我得到了同样的控制台错误。

【问题讨论】:

    标签: reactjs firebase google-cloud-firestore react-hooks firebase-security


    【解决方案1】:

    firestore 安全规则导致控制台错误。

    您应该将 Firestore 安全性 read 规则设置为 true 并附带条件。

    首先,试试下面的代码。

    例如。允许公共读取访问

    service cloud.firestore {
      match /databases/{database}/documents {
        match /impact_metrics/{impactMetricId} {
          allow read: if true;
        }
      }
    }
    

    其次,你应该设置任何你想要的条件。

    见:

    【讨论】:

    • 感谢您的建议。尽管入门工具包附带不包含条件的开发模式规则,但我尝试了您的建议。我犯了同样的错误。我还尝试选择 v2 安全规则,但仍然无法解决这个问题。感谢您提供帮助。
    • 您能否在 Firebase 控制台中测试您的 Firebase 安全规则,使用规则游乐场?见firebase.google.com/docs/rules/simulator
    猜你喜欢
    • 1970-01-01
    • 2020-03-31
    • 1970-01-01
    • 2017-10-21
    • 2021-03-14
    • 2020-04-23
    • 1970-01-01
    • 2021-05-17
    • 1970-01-01
    相关资源
    最近更新 更多