尝试从 Firestore 获取和更新集合时发现“文档集合中未定义”

Posted

技术标签:

【中文标题】尝试从 Firestore 获取和更新集合时发现“文档集合中未定义”【英文标题】:Found "Undefined in Document Collection" when try to fetch and update Collection from Firestore 【发布时间】:2020-03-22 18:49:16 【问题描述】:

我还是新手,还在使用 react 和 firebase 进行自学,请帮我处理这段代码。

我尝试使用带有 react 和 material-ui 的表单从 firestore 收集数据 获取和更新数据 ,

在我更新 useEffect 函数后,没有发现错误,只是没有按我的预期工作。

attached file firestore location picture

  import React,  useState, useEffect  from 'react';

 // material-ui
 import TextField from '@material-ui/core/TextField';
 import Button from '@material-ui/core/Button';
 import Grid from '@material-ui/core/Grid';
 import Typography from '@material-ui/core/Typography';

// firebase
 import  useFirebase  from '../../../components/FirebaseProvider';
 import  useDocument  from 'react-firebase-hooks/firestore';

import AppPageLoading from '../../../components/AppPageLoading';
import  useSnackbar  from 'notistack';

函数

function EditProduk( match ) 

const  firestore, user  = useFirebase();
const  enqueueSnackbar  = useSnackbar();
const produkTraining = firestore.doc(`userdoc/$user.uid/training/$match.params.trainingId`);

const [snapshot, loading] = useDocument(produkTraining);

const [form, setForm] = useState(
    name: '',
    trainer: '',
    price: 0,
    description: ''
);

const [error, setError] = useState(
    name: '',
    trainer: '',
    price: '',
    description: ''
)

const [isSubmitting, setSubmitting] = useState(false);

useEffect(() => 
    if (snapshot) 

        setForm(currentForm => (
            ...currentForm,
            ...snapshot.data()
        ));
    
, [snapshot]);

const handleChange = e => 

    setForm(
        ...form,
        [e.target.name]: e.target.value
    )

    setError(
        ...error,
        [e.target.name]: ''

    )


const validate = () => 
    const newError =  ...error ;

    if (!form.name) 
        newError.name = 'Training name must be filled';
    
    if (!form.trainer) 
        newError.trainer = 'trainer name must be filled';
    
    if (!form.price) 
        newError.price = 'price must be filled';
    
    if (!form.description) 
        newError.description = 'description must be filled';
    
    return newError




const handleSubmit = async e => 
    e.preventDefault();

    const findErrors = validate();

    if (Object.values(findErrors).some(err => err !== '')) 
        setError(findErrors);
     else 
        setSubmitting(true);
        try 
            await produkTraining.set(form,  merge: true );
            enqueueSnackbar('Data has been saved',  variant: 'success' )
        
        catch (e) 
            enqueueSnackbar(e.message,  variant: 'error' )
        
        setSubmitting(false);
    



if (loading) 
    return <AppPageLoading />


return <div>
    <Typography variant="h5" component="h1">Edit Training: form.name</Typography>
    <Grid container alignItems="center" justify="center">
        <Grid item xs=12 sm=6>
            <form id="produk-form" onSubmit=handleSubmit noValidate>
                <TextField
                    id="name"
                    name="name"
                    label="Training Name"
                    margin="normal"
                    required
                    fullWidth
                    value=form.name
                    onChange=handleChange
                    helperText=error.name
                    error=error.name ? true : false
                    disabled=isSubmitting
                />

firestore 规则

 service cloud.firestore 
  match /databases/database/documents 
   match /userdoc/uid 
    allow read: if request.auth.uid == uid;
    allow write: if request.auth.uid == uid;

    match /training/trainingId
    allow read, write: if request.auth.uid == uid;
    
   
  
 

请给我一些建议

【问题讨论】:

@AtinSingh 我不确定这个。签出此代码沙箱codesandbox.io/s/… 【参考方案1】:

首先,如果你想测试firestore规则,有一个很好的选择(firestore模拟器,你可以在firebase consol中找到它)你可以在其中指定很多不同的参数并测试你是否可以访问数据或不基于特定场景。

据我了解,您希望从 firestore 获取数据,将其放入表单,可能会编辑数据并将其保存回数据库。

您收到的错误与 firestore 或其规则无关,因为目前似乎未定义 form 变量。

试试这个:

async function EditProduk( match ) 

...

const [snapshot, loading] = await useDocument(trainingDoc);

【讨论】:

是的,先生,我想从 Firestore 中获取数据,将其放入表单中,可能会编辑数据并将其保存回数据库 @jawara 我认为问题在于你不会等待 useDocument,所以我猜在那一行之后,useEffect 会将表单变量设置为未定义。为此使用异步操作。【参考方案2】:

要消除错误,您需要将value=form.name 替换为value=form &amp;&amp; form.name &amp;&amp; form.name

还有

useEffect(() => 
    if (snapshot.exists) 
        setForm(snapshot.data());
    
, [snapshot]);

【讨论】:

获取数据是一个单独的问题。为了帮助解决这个问题,请打开一个新问题并向我们展示 useFirebase()useDocument() 如何工作并记录 match.params.trainingId,以便我们知道这是一个有效的参考。 我说你是对的先生,但我仍然没有找到解决方案,你可以看到我附上的图片,不是针对 ID 集合,而是使用“未定义”集合 ID 创建一个新的集合 ID 您刚刚更改了整个问题?那不酷。如果我回答了您的原始问题,请授予我答案并打开一个新问题。你不能只是不断地改变你的问题,所有的回答对于以后阅读这篇文章的任何人来说都是断章取义的。我不赞成。

以上是关于尝试从 Firestore 获取和更新集合时发现“文档集合中未定义”的主要内容,如果未能解决你的问题,请参考以下文章

从 Firestore 的一个集合中获取所有文档

大型集合的 Firestore DeadlineExceeded 异常

无法从 Firestore 集合中读取

Firestore - 从集合中的文档中获取集合条目

如何从 firestore 两个集合中获取数据并将所有数据合并在一起

Firestore:仅当有更新时才从服务器获取数据,否则从缓存中获取