You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter点击DataTable中DataRow调用setState提示状态未挂载求助

问题原因与解决方案

问题根源

你在MyDataTableSource的getRow方法里调用_MyHomePageState().update()时,新建了一个完全独立的_MyHomePageState实例。这个新实例从未被Flutter挂载到Widget树中,所以mounted属性为false,触发了你的debugPrint('Not mounted')日志。更关键的是,这个实例和页面上正在运行的真实状态实例毫无关联,就算能执行也不会更新页面状态。

解决方案

核心是让MyDataTableSource通过回调通知父组件(MyHomePage)执行状态更新,而非自行创建状态实例。

修改步骤

  1. 给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;
}
  1. 在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), // 传入父组件的更新方法
),
  1. (可选)你重写的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 04:20:55