React结合Firebase实时数据库使用bootstrap-table时表格误报无匹配记录、搜索排序清空
问题根因
- bootstrap-table 是基于 jQuery 的非 React 组件,初始化时会读取DOM初始状态生成内部维护的数据集,后续DOM的手动变更不会被插件感知
- 现有代码中组件首次渲染时
contactObjects为空对象,此时bootstrap-table已经完成初始化,内部记录的是空数据集 - 后续Firebase返回数据、React重新渲染塞入的
<tr>属于直接DOM操作,没有同步到bootstrap-table的内部状态,因此触发空数据集的“No matching records found”提示;触发搜索/排序时插件会按内部空数据集重绘DOM,覆盖掉手动塞入的内容,导致表格清空
解决方案
两种实现路径二选一即可:
方案1:数据加载完成后再手动初始化bootstrap-table(适配现有渲染逻辑)
- 移除table标签上自动触发初始化的
data-toggle="table"属性 - 通过ref获取table的DOM节点
- 监听数据状态变化,待数据加载完成后再执行插件初始化,同时先销毁历史实例避免重复初始化冲突
- 为列表渲染的
<tr>补充唯一key,消除React渲染警告
import React, { useState, useEffect, useRef } from "react"; import $ from "jquery"; import "bootstrap-table"; import firebaseDb from "../firebase"; const StarTrekTable = () => { const [contactObjects, setObjects] = useState({}); const tableRef = useRef(null); useEffect(() => { firebaseDb.child("unwatched").on("value", (snapshot) => { if (snapshot.val() != null) setObjects({...snapshot.val()}); }); }, []); // 数据加载完成后初始化插件 useEffect(() => { if (Object.keys(contactObjects).length > 0 && tableRef.current) { $(tableRef.current).bootstrapTable("destroy"); $(tableRef.current).bootstrapTable({ pagination: true, search: true }); } }, [contactObjects]); return ( <> <div className="jumbotron jumbotron-fluid"> <div className="container"> <h1 className="display-4 text-center">Star trek series</h1> </div> </div> <div> <div className="col-md-12"> <table ref={tableRef}> <thead className="thread-light"> <tr> <th>Title</th> <th>Series</th> <th>Season</th> <th>Episode</th> <th>Stardate</th> <th>Air Date</th> </tr> </thead> <tbody> {Object.keys(contactObjects).map((id) => { return ( <tr key={id}> <td>{contactObjects[id].title}</td> <td>{contactObjects[id].series}</td> <td>{contactObjects[id].season}</td> <td>{contactObjects[id].episode}</td> <td>{contactObjects[id].stardate}</td> <td>{contactObjects[id].airdate}</td> </tr> ); })} </tbody> </table> </div> </div> </> ); }; export default StarTrekTable;
方案2:直接向插件传数据,完全适配bootstrap-table工作机制
这种方式不需要手动渲染tbody,插件会自行完成渲染,稳定性更高:
- 将Firebase返回的对象数据转为数组格式存储
- 移除手动渲染的tbody逻辑,通过table的
data-data属性直接绑定数据源 - 为每个th指定匹配的
data-field,对应数据数组中的字段名
核心代码片段:
// 状态中存储数组格式的表格数据 const [tableData, setTableData] = useState([]); useEffect(() => { firebaseDb.child("unwatched").on("value", (snapshot) => { if (snapshot.val() != null) { // 将对象转为数组 const dataArr = Object.values(snapshot.val()); setTableData(dataArr); } }); }, []); // table组件代码 <table ref={tableRef} data-pagination="true" data-search="true" data-data={tableData} > <thead> <tr> <th data-field="title">Title</th> <th data-field="series">Series</th> <th data-field="season">Season</th> <th data-field="episode">Episode</th> <th data-field="stardate">Stardate</th> <th data-field="airdate">Air Date</th> </tr> </thead> </table>
补充注意点
- React代码中HTML的
class属性必须替换为className,否则会触发控制台警告 - 项目需正确引入Bootstrap、bootstrap-table、jQuery对应的CSS和JS依赖,确保插件功能正常
- 数据更新时注意销毁旧的插件实例,避免多个实例共存导致的状态异常
内容的提问来源于stack exchange,提问作者First man on the sun
相关产品推荐
相关产品推荐

