React useEffect中数据过滤的刷新异常问题排查
React组件数据加载时序问题分析与解决
问题场景
本地开发时组件首次加载数据正常,但部署到线上环境后出现加载错误;本地刷新页面时,控制台会先打印正确的id和空数组,之后才会加载到完整数据。
组件原代码
const { id } = useParams(); const { tripData, facilityData } = useContext(AppContext); const [data, setData] = useState([]); useEffect(() => { const idResults = facilityData.filter(facility => facility.id === id); if (idResults.length > 0) { setData(idResults[0]); } }, [])
变量说明
[data, setData]:用于填充页面容器的状态facilityData:从AppContext中获取的数据集id:从URL参数中提取的目标资源ID
排查时修改的代码
const { id } = useParams(); const { tripData, facilityData } = useContext(AppContext); const [data, setData] = useState([]); useEffect(() => { const idResults = facilityData.filter(facility => facility.id === id); if (idResults.length > 0) { setData(idResults[0]); } else if (idResults.length === 0) { console.log(`id: ${id}`) console.log(`len: ${idResults}`) } }, [])
App.js中Firebase数据获取代码
import { collection, getDocs } from "firebase/firestore"; import { db } from "./firebase"; const [truckData, setTruckData] = useState([]); const [facilityData, setFacilityData] = useState([]); const [tripData, setTripData] = useState([]); useEffect(() => { const fetchData = async (resource, setter) => { let list = []; try { const querySnapshot = await getDocs(collection(db, resource)); querySnapshot.forEach((doc) => { let docData = doc.data(); if (resource === "trips") { docData.startDate = docData.startDate.toDate(); docData.endDate = docData.endDate.toDate(); } list.push({ id: doc.id, ...docData }); }); setter(list); } catch (error) { console.log(error); } }; fetchData("trucks", setTruckData); fetchData("facilities", setFacilityData); fetchData("trips", setTripData); }, []);
现象原因
- 时序不匹配:组件的
useEffect依赖为空数组,仅在组件挂载时执行一次。此时AppContext中的facilityData还是初始空数组(Firebase异步请求尚未完成),所以过滤后得到空结果,控制台打印空数组。 - 环境差异:本地开发环境中,数据加载完成后组件会自动重新渲染,后续能获取到正确数据;但线上托管服务可能因缓存策略、资源加载顺序或网络延迟,导致组件未重新触发数据匹配逻辑,最终出现错误。
解决方案
1. 修正useEffect依赖项
给组件的useEffect添加id和facilityData作为依赖,确保当URL参数变化或数据集更新时,重新执行过滤逻辑:
const { id } = useParams(); const { tripData, facilityData } = useContext(AppContext); const [data, setData] = useState([]); useEffect(() => { const idResults = facilityData.filter(facility => facility.id === id); if (idResults.length > 0) { setData(idResults[0]); } else { console.log(`id: ${id}`) console.log(`len: ${idResults.length}`) } }, [id, facilityData]) // 添加依赖项
2. 添加加载状态提示
在组件中判断facilityData是否为空,显示加载提示提升用户体验:
if (!facilityData.length) { return <div>加载中...</div>; } // 后续渲染逻辑
3. 优化数据获取逻辑
在App.js中使用Promise.all等待所有数据请求完成后再更新状态,避免子组件拿到不完整的数据集:
useEffect(() => { const fetchData = async (resource) => { let list = []; try { const querySnapshot = await getDocs(collection(db, resource)); querySnapshot.forEach((doc) => { let docData = doc.data(); if (resource === "trips") { docData.startDate = docData.startDate.toDate(); docData.endDate = docData.endDate.toDate(); } list.push({ id: doc.id, ...docData }); }); return list; } catch (error) { console.log(error); return []; } }; const loadAllData = async () => { const [trucks, facilities, trips] = await Promise.all([ fetchData("trucks"), fetchData("facilities"), fetchData("trips") ]); setTruckData(trucks); setFacilityData(facilities); setTripData(trips); }; loadAllData(); }, []);
最终排查结果
经过详细排查,问题并非出自项目代码本身,而是由托管服务的配置或特性导致。
内容的提问来源于stack exchange,提问作者jwald3
相关产品推荐
相关产品推荐

