React+TypeScript中Firebase异步数据传入表格变量及useState报错问题
React+TS项目Firebase异步数据对接表格组件实现方案
问题描述
在React + TypeScript项目中,需要拉取Firebase实时数据库数据传递给自定义表格组件渲染,初始实现存在两个核心问题:
- 时序异常:表格初次渲染时机早于Firebase异步数据返回完成,无法渲染拉取到的数组内容
- 类型报错:尝试使用
useState管理表格数据时出现TypeScript类型不匹配问题
初始问题代码如下:
const data = useMemo<DummyDataType[]>( () => [ { userId: "Foo", flowAmount: "Bar", }, ], [] ); const arr: { userId: string; flowAmount: string }[] = []; var leadsRef = db.ref('users'); leadsRef.on('value', function(snapshot) { snapshot.forEach(item => { arr.push({userId: 'test', flowAmount: 'test'}) }) }); const Table = useTable<DummyDataType>({ columns: columns, data: data, isDataLoading: false, isDataLoadingError: false, isRowSelectable: false, isMultiRowSelectable: false, }); return ( <Box p="4" color="white" bg="rgb(35, 36, 41)"> <Button colorScheme='yellow' > Save changes</Button> {Table} </Box> );
尝试用useState重构数据定义时的错误写法:
type DummyDataType = { userId: ReactNode; flowAmount: ReactNode; }; const data = useState<DummyDataType[]>( () => [ { userId: "Foo", flowAmount: "Bar", }, ], [] );
问题根因
- 异步渲染逻辑错误:Firebase的
on('value')是异步监听回调,普通作用域数组arr不会触发组件重渲染,每次组件重渲染时arr都会被重置为空数组,表格无法感知数据更新 useState语法错误:useState的返回值是*[状态值, 状态更新函数]*的二元元组,直接将返回值整体传给表格data参数会触发类型错误;同时useState仅接收1个初始化参数,多传的第二个空数组属于无效语法- 存在内存泄漏风险:Firebase实时监听未在组件卸载时解绑,会导致重复监听、内存占用异常
正确实现代码
import { useState, useEffect } from 'react'; // 按项目实际依赖引入对应组件 import { Box, Button } from '@chakra-ui/react'; // 类型定义:字段为普通字符串时直接定义为string类型,无需使用ReactNode type DummyDataType = { userId: string; flowAmount: string; }; const DataTablePage = () => { // 定义表格数据、加载状态,useState仅传入一个初始值参数 const [tableData, setTableData] = useState<DummyDataType[]>([ { userId: "Foo", flowAmount: "Bar", } ]); const [isDataLoading, setIsDataLoading] = useState<boolean>(true); useEffect(() => { const leadsRef = db.ref('users'); // 数据变更回调 const handleDataSnapshot = (snapshot: any) => { const fetchedList: DummyDataType[] = []; snapshot.forEach((item: any) => { // 替换为实际的Firebase字段取值逻辑 const itemData = item.val(); fetchedList.push({ userId: itemData.userId || '', flowAmount: itemData.flowAmount || '' }) }); // 更新状态触发组件重渲染 setTableData(fetchedList); setIsDataLoading(false); }; // 绑定Firebase实时监听 leadsRef.on('value', handleDataSnapshot); // 组件卸载时解绑监听,避免内存泄漏 return () => { leadsRef.off('value', handleDataSnapshot); } }, []); const Table = useTable<DummyDataType>({ columns: columns, data: tableData, isDataLoading: isDataLoading, isDataLoadingError: false, isRowSelectable: false, isMultiRowSelectable: false, }); return ( <Box p="4" color="white" bg="rgb(35, 36, 41)"> <Button colorScheme='yellow'>Save changes</Button> {Table} </Box> ); }; export default DataTablePage;
关键修正点
- 修正
useState用法:通过解构获取状态值tableData和更新方法setTableData,仅传入1个初始化参数,从根源解决类型报错 - 异步逻辑移入
useEffect:组件挂载后再绑定Firebase监听,数据返回后通过更新状态触发组件重渲染,解决时序不同步问题 - 增加真实加载状态:数据拉取过程中表格可展示加载态,避免空数据异常展示
- 增加监听清理逻辑:组件卸载时移除Firebase监听,避免内存泄漏
- 优化类型定义:普通文本字段直接定义为
string类型,减少不必要的类型兼容问题
内容的提问来源于stack exchange,提问作者like who
相关产品推荐
相关产品推荐

