Flutter Web中如何通过StreamBuilder将Firestore数据展示在PaginatedDataTable或DataTable
问题解决方法
报错根因
你遇到的报错是因为修改后的UsersData数据源类需要接收Firestore返回的文档数据作为入参,你在实例化时未传入对应参数,同时没有处理空安全校验和Firestore数据类型转换导致的。
完整实现代码
下面的代码同时支持Stream实时监听Firestore数据、行选中、行点击功能,更换集合时仅需修改Stream对应的集合路径即可:
import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:flutter/material.dart'; class AdminDashboard extends StatefulWidget { const AdminDashboard({Key? key}) : super(key: key); @override _AdminDashboardState createState() => _AdminDashboardState(); } class _AdminDashboardState extends State<AdminDashboard> { // 更换集合时仅需修改此处的集合名称即可 final CollectionReference _usersCollection = FirebaseFirestore.instance.collection('users'); @override Widget build(BuildContext context) { return Scaffold( body: SingleChildScrollView( padding: const EdgeInsets.all(16), child: StreamBuilder<QuerySnapshot>( stream: _usersCollection.snapshots(), builder: (context, snapshot) { // 加载状态 if (snapshot.connectionState == ConnectionState.waiting) { return const Center(child: CircularProgressIndicator()); } // 错误状态 if (snapshot.hasError) { return Center(child: Text('加载失败:${snapshot.error}')); } // 无数据状态 if (!snapshot.hasData || snapshot.data!.docs.isEmpty) { return const Center(child: Text('暂无用户数据')); } // 有数据时初始化数据源 final userDocs = snapshot.data!.docs; final UsersData usersData = UsersData(userDocs: userDocs); return PaginatedDataTable( header: const Text("用户列表"), rowsPerPage: 9, showCheckboxColumn: true, // 显示行选中复选框 columns: const [ DataColumn(label: Text('Uid')), DataColumn(label: Text('Name')), DataColumn(label: Text('Email')), DataColumn(label: Text('Role')) ], source: usersData, ); }, ), ), ); } } class UsersData extends DataTableSource { final List<QueryDocumentSnapshot> userDocs; // 存储选中的行索引 final Set<int> _selectedRows = {}; UsersData({required this.userDocs}); @override DataRow getRow(int index) { final user = userDocs[index].data() as Map<String, dynamic>; return DataRow.byIndex( index: index, selected: _selectedRows.contains(index), // 行选中/点击逻辑 onSelectChanged: (value) { if (value != null) { _selectedRows.clear(); if (value) { _selectedRows.add(index); // 此处添加行点击后要执行的逻辑,比如打开详情页 debugPrint('选中的用户数据:${user.toString()}'); } notifyListeners(); } }, cells: [ DataCell(Text(user['uid'] ?? '')), DataCell(Text(user['name'] ?? '')), DataCell(Text(user['email'] ?? '')), DataCell(Text(user['role'] ?? '')), ], ); } @override bool get isRowCountApproximate => false; @override int get rowCount => userDocs.length; @override int get selectedRowCount => _selectedRows.length; }
可选适配方案
如果不需要实时数据更新,仅需单次拉取,可将StreamBuilder替换为FutureBuilder,将stream参数替换为_usersCollection.get()即可。
如果要使用普通DataTable而非分页表格,直接在snapshot.hasData分支中遍历userDocs生成DataRow列表传给DataTable的rows参数即可。
内容的提问来源于stack exchange,提问作者user3030327
相关产品推荐
相关产品推荐

