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

Flutter PaginatedDataTable切换分页仅加载无数据问题求助

问题排查与修复方案

核心问题分析

你的代码存在几个关键问题导致切换分页后无法展示数据:

  • API请求未使用传入的页码参数:fetchDataFromApi方法接收了pageIndex参数,但实际拼接URL时误用了类内部的_pageIndex变量,导致切换页面时请求的页码始终不变。
  • 总行数计算逻辑错误:rowCount使用位运算_data.length | _rowCount,这会导致数值异常,PaginatedDataTable无法正确计算总页数和分页状态。
  • 分页参数未同步:数据源内部的_rowsPerPage、_pageIndex未与外部组件的状态同步,导致分页参数不一致。
  • 页码索引混乱:外部组件页码从0开始,内部从1开始,切换页面时的加1操作进一步加剧了参数混乱。

修复后的完整代码

import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:mobile_ess/helpers/url_helper.dart';
import 'package:shared_preferences/shared_preferences.dart';

class PicHrgs extends StatefulWidget {
  const PicHrgs({super.key});

  @override
  State<PicHrgs> createState() => _PicHrgsState();
}

class _PicHrgsState extends State<PicHrgs> {
  final MyDataSource dataSource = MyDataSource();
  late int _rowsPerPage = PaginatedDataTable.defaultRowsPerPage;
  // 统一使用从1开始的页码,和API保持一致
  late int _currentPage = 1;

  @override
  Widget build(BuildContext context) {
    return SingleChildScrollView(
      child: PaginatedDataTable(
        columns: const <DataColumn>[
          DataColumn(label: Text('NRP')),
          DataColumn(label: Text('Nama')),
        ],
        source: dataSource,
        rowsPerPage: _rowsPerPage,
        onRowsPerPageChanged: (value) {
          setState(() {
            _rowsPerPage = value!;
            // 切换每页条数后回到第一页
            _currentPage = 1;
            dataSource.fetchDataFromApi(pageIndex: _currentPage, rowsPerPage: _rowsPerPage);
          });
        },
        onPageChanged: (pageIndex) {
          setState(() {
            // PaginatedDataTable的pageIndex从0开始,转换为API需要的从1开始的页码
            _currentPage = pageIndex + 1;
            dataSource.fetchDataFromApi(pageIndex: _currentPage, rowsPerPage: _rowsPerPage);
          });
        },
        availableRowsPerPage: const [5, 10, 20, 100],
      ),
    );
  }

  @override
  void initState() {
    super.initState();
    dataSource.addListener(() {
      setState(() {});
    });
    dataSource.fetchDataFromApi(pageIndex: _currentPage, rowsPerPage: _rowsPerPage);
  }
}

class MyDataSource extends DataTableSource {
  List<List<Comparable<Object>>> _data = [];
  int _totalRecords = 0;
  bool _isLoading = false;
  final String apiUrl = API_URL;

  Future<void> fetchDataFromApi({required int pageIndex, required int rowsPerPage, String searchQuery = ''}) async {
    setStateLoading(true);
    SharedPreferences prefs = await SharedPreferences.getInstance();
    String? token = prefs.getString('token');

    try {
      final response = await http.get(
        Uri.parse("$apiUrl/master/hrgs/get?page=$pageIndex&perPage=$rowsPerPage&search=$searchQuery"),
        headers: <String, String>{
          "Content-Type": "application/json;charset=UTF-8",
          'Authorization': 'Bearer $token',
        },
      );

      if (response.statusCode == 200) {
        final Map<String, dynamic> responseData = json.decode(response.body);
        final List<dynamic> dataku = responseData['dataku'];
        final total = responseData["totalPage"];
        
        _totalRecords = total['total_records'] ?? 0;
        _data = dataku.map<List<Comparable<Object>>>((data) {
          return [
            data['nrp'] ?? '',
            data['nama'] ?? '',
          ];
        }).toList();
      } else {
        throw Exception('Failed to load data');
      }
    } catch (e) {
      debugPrint(e.toString());
    } finally {
      setStateLoading(false);
      notifyListeners();
    }
  }

  void setStateLoading(bool loading) {
    _isLoading = loading;
    notifyListeners();
  }

  @override
  DataRow? getRow(int index) {
    if (index >= 0 && index < _data.length) {
      return DataRow(cells: <DataCell>[
        DataCell(Text(_data[index][0].toString())),
        DataCell(Text(_data[index][1].toString())),
      ]);
    }
    // 加载状态下显示加载单元格
    if (_isLoading) {
      return DataRow(cells: List.generate(2, (index) => const DataCell(CircularProgressIndicator())));
    }
    return null;
  }

  @override
  bool get isRowCountApproximate => false;

  @override
  int get rowCount => _isLoading ? _data.length + 1 : _totalRecords;

  @override
  int get selectedRowCount => 0;
}

关键修复点说明

  1. 统一页码索引:外部组件将页码转换为API需要的从1开始的格式,避免索引混乱。
  2. 正确传递分页参数:fetchDataFromApi方法接收rowsPerPage和pageIndex参数,并直接用于API请求,确保参数同步。
  3. 修复总行数逻辑:rowCount根据加载状态返回对应数值,加载时显示额外的加载行,正常状态返回总记录数。
  4. 添加加载状态管理:新增_isLoading状态,在请求过程中显示加载指示器,提升用户体验。
  5. 移除冗余状态:去掉数据源内部冗余的_pageIndex和_rowsPerPage变量,直接使用外部传入的参数。

内容的提问来源于stack exchange,提问作者Mr. X

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 20:55:54