Flutter点击DataTable中DataRow调用setState提示状态未挂载求助
问题原因与解决方案
问题根源
你在MyDataTableSource的getRow方法里调用_MyHomePageState().update()时,新建了一个完全独立的_MyHomePageState实例。这个新实例从未被Flutter挂载到Widget树中,所以mounted属性为false,触发了你的debugPrint('Not mounted')日志。更关键的是,这个实例和页面上正在运行的真实状态实例毫无关联,就算能执行也不会更新页面状态。
解决方案
核心是让MyDataTableSource通过回调通知父组件(MyHomePage)执行状态更新,而非自行创建状态实例。
修改步骤
- 给
MyDataTableSource添加回调参数,用于传递更新逻辑:
class MyDataTableSource extends DataTableSource { final VoidCallback onUpdate; MyDataTableSource({required this.onUpdate}); @override DataRow getRow(int index) { return DataRow.byIndex( index: index, cells: <DataCell>[ DataCell(GestureDetector( onTap: () => onUpdate(), // 调用传入的回调 child: const Text('Sarah'), )), DataCell(GestureDetector( onTap: () => onUpdate(), child: const Text('19'), )), DataCell(GestureDetector( onTap: () => onUpdate(), child: const Text('Student'), )), ], ); } @override bool get isRowCountApproximate => false; @override int get rowCount => 3; @override int get selectedRowCount => 0; }
- 在
MyHomePage的build方法中,创建MyDataTableSource实例时传入update方法:
body: PaginatedDataTable( showCheckboxColumn: true, columns: const <DataColumn>[ DataColumn( label: Expanded( child: Text( 'Name', style: TextStyle(fontStyle: FontStyle.italic), ), ), ), DataColumn( label: Expanded( child: Text( 'Age', style: TextStyle(fontStyle: FontStyle.italic), ), ), ), DataColumn( label: Expanded( child: Text( 'Role', style: TextStyle(fontStyle: FontStyle.italic), ), ), ), ], source: MyDataTableSource(onUpdate: update), // 传入父组件的更新方法 ),
- (可选)你重写的
setState方法可以移除,Flutter原生的State类会自动忽略未挂载状态下的setState调用,保留日志的话也可以继续使用。
完整修改后代码
import 'package:flutter/material.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return const MaterialApp( title: 'Flutter Demo', home: MyHomePage(), ); } } class MyHomePage extends StatefulWidget { const MyHomePage({super.key}); @override State<MyHomePage> createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { @override setState(fn){ if (mounted) { super.setState(fn); } else { debugPrint('Not mounted'); } } update() => setState((){}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Flutter Demo'), ), body: PaginatedDataTable( showCheckboxColumn: true, columns: const <DataColumn>[ DataColumn( label: Expanded( child: Text( 'Name', style: TextStyle(fontStyle: FontStyle.italic), ), ), ), DataColumn( label: Expanded( child: Text( 'Age', style: TextStyle(fontStyle: FontStyle.italic), ), ), ), DataColumn( label: Expanded( child: Text( 'Role', style: TextStyle(fontStyle: FontStyle.italic), ), ), ), ], source: MyDataTableSource(onUpdate: update), ), ); } } class MyDataTableSource extends DataTableSource { final VoidCallback onUpdate; MyDataTableSource({required this.onUpdate}); @override DataRow getRow(int index) { return DataRow.byIndex( index: index, cells: <DataCell>[ DataCell(GestureDetector( onTap: () => onUpdate(), child: const Text('Sarah'), )), DataCell(GestureDetector( onTap: () => onUpdate(), child: const Text('19'), )), DataCell(GestureDetector( onTap: () => onUpdate(), child: const Text('Student'), )), ], ); } @override bool get isRowCountApproximate => false; @override int get rowCount => 3; @override int get selectedRowCount => 0; }
内容的提问来源于stack exchange,提问作者Savado
相关产品推荐
相关产品推荐

