通过React挂钩读取Firestore数据

时间:2020-08-09 00:33:35

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

我正在尝试找出如何通过react钩子从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;
    }

尝试此操作时,出现相同的控制台错误。

1 个答案:

答案 0 :(得分:0)

控制台错误是由Firestore安全规则引起的。

您应根据条件将Firestore安全性read规则设置为true

首先,尝试以下代码。

例如允许公众阅读权限

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

第二,您应该设置所需的任何条件。

请参阅: