反应useEffect一次获取Firestore数据

时间:2020-04-12 22:15:08

标签: javascript reactjs google-cloud-firestore jsx

我正在尝试弄清楚如何使用react useEffect从Firestore获取数据。

这是我目前的尝试。

import React, { useHook, useEffect, useState } from 'react';
import {
    useParams
  } from 'react-router-dom';

import Firebase from "../../../firebase";

 const ReadBlogPost = async () => {
    const [loading, setLoading] = useState(true);
    const [currentPost, setCurrentPost] = useState([]);
    let { slug } = useParams();


      useEffect(()  =>  {
          Firebase
          .firestore
          .collection("blog")
          .doc(slug)
          .get()
          .then(function(doc) {
            if (doc.exists) {
                // setCurrentPost(doc.data());
                console.log("Document data:", doc.data());
            } else {
                // doc.data() will be undefined in this case
                console.log("No such document!");
            }
          })
          .catch(function(error) {
            console.log("Error getting document:", error);
        }), []
      })

    return (
        <div>

                    {currentPost.title}


        </div>
    )

};
export default ReadBlogPost;

最后的空数组是一种尝试,以确保React不会用尽this postthis issue中详细说明的所有Firestore读取配额。

尝试此操作时,出现错误消息:

第19:11行:希望进​​行赋值或函数调用,而是看到了 表达式no-unused-expressio

文件是jsx。我已经看到this postthis,这意味着我必须将if语句转换为三元条件。

我尝试将其更改为三元表达式是

useEffect(()  =>  {
          Firebase
          .firestore
          .collection("blog")
          .doc(slug)
          .get()
          .then(function(doc) {
            doc.exists? setCurrentPost(doc.data()) :  console.log("No such document!")
          })
          .catch(function(error) {
            console.log("Error getting document:", error);
        }), []
      })

尝试此操作时,会收到与使用if语句时相同的错误消息。

有人可以举一个使用useEffect一次读取jsx文件中的Firestore数据的示例吗?

下次尝试 根据尼古拉斯的建议,我将useEffect更改为:

useEffect(()  =>  {
          Firebase
          .firestore
          .collection("blog")
          .doc(slug)
          .get()
          .then(function(doc) {
            doc.exists? setCurrentPost(doc.data()) :  console.log("No such document!")
          .catch(function(error) {
                console.log("Error getting document:", error)
          })  
        }, [])
      })

这会产生一个错误,提示:

错误:对象作为React子对象无效(找到:[object 诺言])。如果您打算渲染儿童集合,请使用 而不是数组。

下一个尝试

我尝试了Ben的建议-将currentPost中的对象更改回数组,但是遇到了与尝试Nicholas的建议时相同的错误。

然后,我尝试像这样合并其中的一部分:

import React, { useHook, useEffect, useState } from 'react';
import { useParams } from 'react-router-dom';

import Firebase from "../../../firebase";

const ReadBlogPost = async () => {
    let { slug } = useParams();
    const [loading, setLoading] = useState(true);
    const [currentPost, setCurrentPost] = useState([]);



    useEffect(() => {

        const fetchData = async() => {

            try {
                const response = await Firebase.firestore
                    .collection("blog")
                    .doc(slug)
                    .get()
                    .then(function(doc) {
                        doc.exists? setCurrentPost(doc.data()) :  console.log("No such document!")


                    }) 
                } catch(err) {
                    console.error(err);
                }   
            };         


        fetchData();

    }, []);


    return (
        <div>

            {!loading && 
currentPost.title}


        </div>
    )

};
export default ReadBlogPost;

我仍然遇到相同的错误。

错误:对象作为React子对象无效(找到:[object 诺言])。如果您打算渲染儿童集合,请使用 数组代替。 在ReadBlogPost中(由Context.Consumer创建)

我不知道是否有任何线索,但是ReadBlogPost参考建议我在某个地方有上下文使用者。我尚未创建上下文-因此不确定是否正在寻找一个可以使用useEffect的上下文?

2 个答案:

答案 0 :(得分:1)

您的依赖项数组放置在错误的位置。通过重新格式化以突出显示该问题,您正在执行以下操作:

  useEffect(() => {
    Firebase.firestore
      //...
      .catch(/*...*/), [];
  });

...由于comma operator,在技术上是合法的javascript。但是由于这可能是一个错误,所以您的短毛猫会指出这一点。

相反,您应该这样做:

  useEffect(() => {
    Firebase.firestore
      //...
      .catch(/*...*/);
  }, []);

答案 1 :(得分:1)

使用useEffect获取数据时,它期望进行同步调用。从Firestore询问数据将是异步的,因此要解决此问题,我们可以添加一个包装名为fetchData的firestore调用的函数,如下所示:

import React, { useHook, useEffect, useState } from 'react';
import { useParams } from 'react-router-dom';
import Firebase from "../../../firebase";

function ReadBlogPost () {
    const [loading, setLoading] = useState(true);
    const [currentPost, setCurrentPost] = useState({});
    let { slug } = useParams();


    useEffect(() => {

        const fetchData = async() => {

            try {

                const response = await Firebase.firestore()
                    .collection("blog")
                    .doc(slug)
                    .get();

                console.log('response', response);

                let data = { title: 'not found' };

                if (response.exists) {
                    data = response.data();
                }

                setCurrentPost(data);
                setLoading(false);

            } catch(err) {
                console.error(err);
            }

        };

        fetchData();

    }, []);

    return (
        <div>

            {!loading && currentPost.title}


        </div>
    )

};
export default ReadBlogPost;

考虑到您也在JSX中询问标题,我假设您的currentPost可能是一个对象,而不是一个数组-并且我在fetchData中的Firestore调用之后添加了setCurrentPost。希望对您有帮助

更新:我已经将组件的设置更改为命名的同步组件(删除了顶部的const并删除了异步),并且我还注意到您提到您将currentPost改回了数组-请确保这是一个对象,因为您将JSX中的currentPost引用为对象-我刚刚使用自己的firestore数据库在本地使用了上面编写的代码,并成功地从useEffect中获取了详细信息。请尝试复制上面的整个代码段。如果它不起作用,我还会请您从导入的../firebase中粘贴Firestore参考代码。另外,请不要将.then.catch与try {} catch {}块混合使用,因为它们正试图做同样的事情