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

React-Firebase应用接入Firestore后变慢,如何优化提升运行速度

React-Firebase Firestore卡顿优化方案

核心问题梳理

  • useEffect无依赖数组,每次组件重渲染都会重新注册onSnapshot监听器,导致重复请求、内存泄漏
  • 未设置onSnapshot取消订阅逻辑,组件卸载后监听器仍在后台运行占用资源
  • 未使用Firestore服务端过滤,拉取整个users集合后在前端筛选customer类型用户,数据量越大性能损耗越高
  • update操作逻辑冗余,每次更新用户状态都会全量拉取users集合遍历匹配,单次更新请求成本过高
  • async/await使用错误,onSnapshot是流式监听器不是一次性Promise请求,await无实际作用还会导致逻辑异常

优化方案

  1. 给useEffect添加空依赖数组,保证仅组件挂载时注册一次监听器
  2. 声明onSnapshot返回的取消订阅函数,在useEffect的清理函数中调用,卸载时销毁监听器
  3. 用Firestore的where()方法在服务端直接过滤typeOfUser为customer的用户,减少不必要的数据传输
  4. 拉取用户数据时同时保存文档ID,更新状态时直接用文档ID定位目标文档,无需全量拉取集合
  5. 删除不必要的async/await和冗余遍历逻辑,单次更新仅触发1次接口请求
  6. 修复原代码中状态变量名单复数不匹配的问题,避免意外的重渲染

优化后代码

import React, {useEffect, useState} from 'react'
import firebase from 'firebase/compat'
import { db } from '../firebase.js'
import Navbar from './Navbar'
import './styles/MasterScreen.css'

const MasterScreen = ({typeOfUser}) => {
    const [customers, setCustomers] = useState([])
    useEffect(() => {
        // 注册实时监听,服务端过滤customer类型用户
        const unSubscribe = firebase.firestore()
            .collection('users')
            .where('typeOfUser', '==', 'customer')
            .onSnapshot(snapshot => {
                setCustomers(snapshot.docs.map(doc => ({
                    id: doc.id, // 保存文档ID用于后续更新
                    ...doc.data()
                })))
            })
        // 组件卸载时取消监听
        return () => unSubscribe()
    }, []) // 空依赖仅挂载执行一次

    function changeState(docId, state) {
        // 直接用文档ID定位更新,无需全量拉取
        firebase.firestore().collection('users').doc(docId).update({state})
    }

    return (
        <div>
            <Navbar typeOfUser={typeOfUser} />
            <div className="customers">
                {customers.map(e => (
                    <div key={e.uid} className="customer">
                        <div className={`state ${e.state === 'go' ? 'green' : e.state === 'slow' ? 'yellow' : e.state === 'stop' ? 'red' : 'pause'}`}>
                            <h3>CURRENT STATE</h3>
                        </div>
                        <div className="customerContents">
                            {/* 传文档ID代替uid,如果文档ID本身就是用户uid可直接传e.uid */}
                            <button className='goOne btn' onClick={() => changeState(e.id, 'go')}>GO</button>
                            <button className='slowOne btn' onClick={() => changeState(e.id, 'slow')}>SLOW</button>
                            <button className='stopOne btn' onClick={() => changeState(e.id, 'stop')}>STOP</button>
                            <button className='pauseOne btn' onClick={() => changeState(e.id, 'pause')}>PAUSE</button>
                        </div>
                    </div>
                ))}
            </div>
        </div>
    )
}

export default MasterScreen

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 14:45:05