【问题标题】:Problem when I try to get collection from Firestore当我尝试从 Firestore 获取集合时出现问题
【发布时间】:2026-01-23 07:45:02
【问题描述】:

看到所有答案后,我再次编辑了代码。但是我还是有问题

const getPosts = async () => {
const snapshot = await firestore.collection('posts').get();
const posts = snapshot.docs.map((doc) => ({ ...doc.data() }));

return posts; };


const PostsList = () => {
let postsData = null;
getPosts().then((posts) => {
    postsData = posts;
}); 

console.log(postsData); // null
return postsData.map((post) => <PostItem key={post.id} event={post} />); };

【问题讨论】:

    标签: javascript reactjs firebase google-cloud-firestore


    【解决方案1】:

    你在这里引入了异步代码。

    firestore.collection(`posts`).get().then((snapShot) => {
            snapShot.docs.forEach((doc) => {
                let data = { ...doc.data() };
                posts.unshift(data);
            });
        });
    

    get() 方法返回一个promise,一旦它被解析,它将在 .then() 方法中处理。这意味着,只有 then() 中的内容会等待其执行完成,并且块外的任何内容都会同步执行。

    在您的情况下,所有 console.log() 方法都将在您实际从 Fire 基地获取数据之前执行。要修复它,您可以像 Peter 所说的那样操作 then() 方法中的数据,也可以使用 async/await

    例子:

    var promise1 = new Promise(function(resolve, reject) {
      setTimeout(function() {
        resolve('foo');
      }, 300);
    });
    
    const consoleIt = async () => { // returns a promise implicitly
      value = await promise1;
      console.log('value',value)
    }
    consoleIt(); // Expected output: "value" "foo"
    
    //or
    
    const consoleIt2 = async () => { // returns a promise implicitly
      value = await promise1;
      return value;
    }
    consoleIt2().then(value => console.log('value', value)); // Expected output: "value" "foo"
    
    

    你的代码应该是:

    const getPosts = async () => {
        const posts = [];
        let snapShot = await firestore.collection(`posts`).get(); // rest of the code will wait for the snapShot value.
        snapShot.docs.forEach((doc) => {
                let data = { ...doc.data() };
                posts.unshift(data);
            });
        console.log(posts);  
        console.log(posts.length);  
        console.log(posts[1]);  // Will print the object.
        return posts;
    };
    

    异步函数通常返回 promise。你可以像这样调用这个函数

    const posts = await getPosts(); 要么 getPosts().then((posts)=&gt; {console.log(posts)})

    你的代码应该是这样的

    const PostsList = () => {
    getPosts().then((posts) => {
     console.log(posts); // prints object
     return posts.map((post) => <PostItem key={post.id} event={post} />); };
    }); 
    
    // or if you want to handle no data.
    let posts = null;
    const PostsList = () => {
    getPosts().then((res) => {
    post = res;
     console.log(posts); // prints object
    });
    return posts? posts.map((post) => <PostItem key={post.id} event={post} />) : <NoData/>; 
    }
    
    

    注意:await 关键字只能在异步函数中使用!

    【讨论】:

    • 当我返回帖子对象时,它未定义:(
    • 在函数末尾返回帖子 new func() { const posts = getPosts();控制台日志(帖子); // 未定义 }
    • 你能设置一个代码沙箱,这样我就可以检查问题出在哪里:) codesandbox.io
    • 或者使用您最近的更改更新问题,并添加您从 firebase 获得的 json 数据。有了它,我可以模拟执行并找到缺陷。
    • const 帖子 = getPosts();控制台日志(帖子); // 我认为这行会立即执行,不会等待 getPosts 返回值。 getPosts 函数中的 console.log() 函数是否打印值?
    【解决方案2】:

    我一般建议避免使用 push 来改变数组。也就是说,您可以从函数中返回帖子,以便更轻松地使用它们

    const getPosts = async () => {
        const snapshot = await firestore.collection('posts').get();
        return snapshot.docs.map(snap => Object.assign({}, { ...snap.data() }))
    }
    

    await 关键字会延迟执行依赖于“快照”的代码,直到 Promise 被解决。

    编辑 我把它重新放回原来的形式,因为它简洁易读。问题是 getPost 函数也应该被等待,因为如果你这样做:

    const posts = getPosts()
    

    它将立即使用,而不是等待 getPost() 完成。您可以在 getPosts 中使用 .then,例如:

    getPosts().then(result => console.log(result))
    

    您还可以将使用 getPosts() 的函数包装在 async/await 中,并能够使用它的结果,因为它是一个同步函数。

    请参阅here 了解相关问题和其他解释,以及同一问题中的其他答案。

    【讨论】:

    • 它返回一个承诺而不是一个对象
    • 我编辑了我的答案。它现在应该返回一个对象数组
    • 它仍然返回一个承诺
    • @YudaZvi 我看到了您对回复的编辑(由于缺乏代表,无法添加评论)。为什么将 postData 初始化为 null?如果将其初始化为空数组,您的代码将完美运行
    【解决方案3】:

    get() 返回一个Promise,用于异步代码。

    then() 方法返回一个 Promise。它最多需要两个参数:Promise 成功和失败情况的回调函数。

    因此,then 方法之外的 console.log(posts); 将返回 undefined,因为尚未检索到数据。您需要执行以下操作:

    const getPosts = () => {
        const posts = [];
        firestore.collection(`posts`).get().then((snapShot) => {
            snapShot.docs.forEach((doc) => {
                let data = { ...doc.data() };
                posts.unshift(data);
                console.log(posts);    
                console.log(posts[1]);
    
            });
        });
    };
    

    如果你想在then() 方法之外访问数组,那么你可以返回一个Promise

    const getPosts = () => {
        const posts = [];
      return new Promise((resolve, reject) => {  
      firestore.collection(`posts`).get().then((snapShot) => {
            snapShot.docs.forEach((doc) => {
                let data = { ...doc.data() };
                posts.unshift(data);
                console.log(posts); 
                resolve(posts);  
                console.log(posts[1]);
    
            });
        });
       });
    };
    

    然后您可以执行以下操作:

    getPosts().then((posts) => {
       console.log(posts);
     });
    

    检查以下链接:

    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then

    【讨论】:

    • 但是我想在这个函数之外使用数据
    • 查看答案
    • 让 postsArr = null; getPosts().then((posts) => { postsArr = posts; });控制台.log(postsArr); // 空
    • 谢谢,但我在那里找不到解决方案。我需要将数据从函数中取出并放入一个简单的 const
    最近更新 更多