You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让try/catch等待响应后再继续执行?解决Firestore数据需点击两次按钮才能读取的问题

解决Firestore数据需点击两次按钮才显示的问题

我来帮你拆解下问题根源,再给出针对性的解决方案:

问题核心原因

你的代码里有两个关键问题导致了"点击两次才看到数据"的情况:

  1. useState的异步更新特性
    setData是异步操作,当你在onSnapshot回调里调用setData后,紧接着的console.log(data)并不会立即拿到更新后的state——它打印的还是调用readData时的旧值(也就是初始的空数组)。只有等组件重新渲染后,data才会完成更新,第二次点击按钮时,console.log(data)才会打印出上一次更新后的内容。

  2. onSnapshot是持续监听而非单次读取
    onSnapshot会注册一个实时监听,只要Firestore的users集合有数据变化,回调就会触发。你每次点击按钮都会新增一个监听,这会导致后续数据变化时多次调用setData,重复往数组里添加数据,这显然不是你想要的单次读取效果。

解决方案

根据你的需求,分两种场景处理:

场景1:仅需单次读取数据(不需要实时同步)

把onSnapshot换成get()来获取单次数据快照,同时通过useEffect监听data的变化来打印更新后的数据(或者用setData的回调函数):

import firebase from 'firebase/compat/app'
import 'firebase/compat/firestore';
import { useState, useEffect } from 'react';

export default function ReadToFirebase() {
  const [data, setData] = useState([])

  const readData = async () => {
    try {
      // 单次获取集合数据
      const snapshot = await firebase
        .firestore()
        .collection('users')
        .get();
      
      // 格式化数据,直接生成新数组替换旧数组(避免重复追加)
      const formattedData = snapshot.docs.map(doc => {
        const docData = doc.data();
        return { username: docData.userName, email: docData.email };
      });
      
      setData(formattedData);
      console.log('Data Read!');
    } catch (error) {
      console.log(`Opps! Error querying data: \n\n ${error}`);
      alert(error)
    }
  }

  // 监听data状态变化,更新时打印最新数据
  useEffect(() => {
    if(data.length > 0) {
      console.log('Updated data:', data);
    }
  }, [data])

  return (
    <div className="p-4 grid place-items-center space-y-2">
      <button onClick={readData} className="py-2 px-4 bg-gray-300 rounded-xl font-bold">Read Data</button>
      <div className=""></div>
    </div>
  )
}

场景2:需要实时监听数据变化(数据更新自动刷新)

如果需要实时同步Firestore的集合变化,应该用useEffect注册监听(组件挂载时仅执行一次),避免重复绑定:

import firebase from 'firebase/compat/app'
import 'firebase/compat/firestore';
import { useState, useEffect } from 'react';

export default function ReadToFirebase() {
  const [data, setData] = useState([])

  useEffect(() => {
    // 注册实时监听
    const unsubscribe = firebase
      .firestore()
      .collection('users')
      .onSnapshot(
        snapshot => {
          const formattedData = snapshot.docs.map(doc => {
            const docData = doc.data();
            return { username: docData.userName, email: docData.email };
          });
          setData(formattedData);
          console.log('Data updated:', formattedData);
        },
        error => {
          console.log(`Opps! Error querying data: \n\n ${error}`);
          alert(error)
        }
      );

    // 组件卸载时取消监听,防止内存泄漏
    return () => unsubscribe();
  }, []);

  return (
    <div className="p-4 grid place-items-center space-y-2">
      <div className=""></div>
      {/* 若需要手动触发刷新,可添加按钮调用重新获取逻辑 */}
    </div>
  )
}

额外提示

  • 之前你用setData(oldArray => [...oldArray, data])的方式会导致重复追加数据,换成直接生成新数组替换旧数组的方式更合理。
  • 异步操作中使用async/await能让代码可读性更高。

内容的提问来源于stack exchange,提问作者Alfredo Natal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 17:44:04