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

React 获取数据后state数组更新但页面不渲染问题求助

问题原因
  1. Firebase onSnapshot 是异步回调机制:你写的getBarcodesByUser虽然标记了async,但onSnapshot本身不会返回Promise,函数执行到return result的时候,onSnapshot的回调还没触发,所以返回的永远是空数组。
  2. 数组引用未变更导致React无法检测更新:就算后续onSnapshot回调往原来的result数组里push了数据,你之前setState已经把这个数组的引用存在state里了,修改原数组内容不会触发React的重渲染逻辑,forceUpdate也没用因为你调用的时候数据还没更新。
解决方案

根据是否需要实时数据更新,可选择以下两种方案:

方案1:不需要实时更新,仅拉取一次数据

把getBarcodesByUser里的onSnapshot换成一次性查询的getDocs即可:

export const getBarcodesByUser = async ( uid: string ): string[] => {
  const result = [];
  const q = query(collection(firestore, "qrcode"), where("uid", "==", uid));
  // 用getDocs做一次性查询,支持async/await等待结果返回
  const querySnapshot = await getDocs(q);
  querySnapshot.forEach( document => {
    result.push( document.id )
  })
  return result;
}

修改后原有组件逻辑无需调整,即可正常拿到数据渲染。

方案2:需要保留onSnapshot的实时更新能力

不能把实时监听器当成普通异步Promise函数使用,需要在回调中直接更新组件state,同时要注意组件卸载时清理监听器避免内存泄漏:
首先调整getBarcodesByUser实现:

export const getBarcodesByUser = ( uid: string, callback: (ids: string[]) => void ) => {
  const q = query(collection(firestore, "qrcode"), where("uid", "==", uid));
  // 返回取消监听的方法供组件卸载时调用
  return onSnapshot(q, (querySnapshot) => {
    const result = [];
    querySnapshot.forEach( document => {
      result.push( document.id )
    })
    callback(result);
  })
}

再调整组件调用逻辑:

class MyAttendees extends React.Component {
  static contextType = AuthContext;
  // 存储取消监听的方法
  unsubscribeSnapshot = null;

  constructor(props){
    super(props);
    this.state = {
      barcodesData: []
    }
  }

  componentDidMount() {
    const { currentUser } = this.context;
    const uid = currentUser.uid;
    // 传入回调,拿到数据后直接更新state,新的数组引用会自动触发重渲染
    this.unsubscribeSnapshot = getBarcodesByUser(uid, (data) => {
      this.setState({ barcodesData: data })
    })
  }

  // 组件卸载时清理监听器
  componentWillUnmount() {
    if(this.unsubscribeSnapshot) this.unsubscribeSnapshot();
  }

  render() {
    return (
    <div>
          {
            this.state.barcodesData.map((item) => {
              return <h1 key={item}>{item}</h1>
            })
          }
    </div>
    )
  }
}
export default MyAttendees;

该方案不仅能解决首次渲染问题,后续Firestore中对应数据发生变更时,组件也会自动同步更新。

内容的提问来源于stack exchange,提问作者Ritik Ranjan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 21:45:01