很好地利用FetchMore GQL进行无限滚动分页ListView与Flutter

pok*_*oka 5 graphql flutter

我正在尝试使用graphql-flutter库创建来自 GraphQL API 的元素的 ListView 。

第一页的构建正常。然后当我开始滚动时,结果会很好,我的 ListView 显示第二页,然后第三页等......正确。

问题是,从第二个页面加载开始,就出现了问题。FetchMore 函数似乎在每个页面加载时构建多个请求。就像之前加载的所有页面都再次加载一样,越来越多。

奇怪的是,正如我所说,显示列表的结果在几个页面中都是正确的,然后突然列表从上一页循环回来,然后继续继续......

这是我的查询小部件:

Query(
  options: QueryOptions(
    document: gql(getHistory),
    variables: <String, dynamic>{
      'pubkey': this.pubkey,
      'number': nRepositories,
      'cursor': null
    },
  ),
  builder: (QueryResult result, {refetch, FetchMore fetchMore}) {
    if (result.isLoading && result.data == null) {
      return const Center(
        child: CircularProgressIndicator(),
      );
    }

    if (result.hasException) {
      return Text('\nErrors: \n  ' + result.exception.toString());
    }

    if (result.data == null && result.exception.toString() == null) {
      return const Text('Both data and errors are null');
    }

    final List<dynamic> blockchainTX =
        (result.data['txsHistoryBc']['both']['edges'] as List<dynamic>);

    final Map pageInfo =
        result.data['txsHistoryBc']['both']['pageInfo'];

    final String fetchMoreCursor =
        pageInfo['endCursor'];

    FetchMoreOptions opts = FetchMoreOptions(
      variables: {'cursor': fetchMoreCursor},
      updateQuery: (previousResultData, fetchMoreResultData) {
        final List<dynamic> repos = [
          ...previousResultData['txsHistoryBc']['both']['edges']
              as List<dynamic>,
          ...fetchMoreResultData['txsHistoryBc']['both']['edges']
              as List<dynamic>
        ];

        fetchMoreResultData['txsHistoryBc']['both']['edges'] = repos;
        return fetchMoreResultData;
      },
    );

    _scrollController
      ..addListener(() {
        if (_scrollController.position.pixels ==
            _scrollController.position.maxScrollExtent) {
          if (!result.isLoading) {
            print(
                "DEBUG fetchMoreCursor in scrollController: $fetchMoreCursor");
            fetchMore(opts);
          }
        }
      });

    print(
        "###### DEBUG Parse blockchainTX list. Cursor: $fetchMoreCursor ######");
    List _transBC = parseHistory(blockchainTX);

    return Expanded(
      child: HistoryListView(
          scrollController: _scrollController,
          transBC: _transBC,
          historyData: result),
    );
  },
),
Run Code Online (Sandbox Code Playgroud)

然后小部件HistoryListView根据数据构建列表transBC。这是从应用程序启动时仅加载一页的DEBUG行的打印结果(请参阅上面的代码) :

I/flutter ( 8745): ###### DEBUG Parse blockchainTX list. Cursor: 386237:8A98F83A120EF89FC65CF43BEE77068F3DA5734340B7987FA059D582A06934F8 ######
I/flutter ( 8745): DEBUG fetchMoreCursor in scrollController: 386237:8A98F83A120EF89FC65CF43BEE77068F3DA5734340B7987FA059D582A06934F8
I/flutter ( 8745): ###### DEBUG Parse blockchainTX list. Cursor: 386237:8A98F83A120EF89FC65CF43BEE77068F3DA5734340B7987FA059D582A06934F8 ######
I/flutter ( 8745): DEBUG fetchMoreCursor in scrollController: 386237:8A98F83A120EF89FC65CF43BEE77068F3DA5734340B7987FA059D582A06934F8
I/flutter ( 8745): ###### DEBUG Parse blockchainTX list. Cursor: 386237:8A98F83A120EF89FC65CF43BEE77068F3DA5734340B7987FA059D582A06934F8 ######
I/flutter ( 8745): ###### DEBUG Parse blockchainTX list. Cursor: 384695:4BF72317A538FB37F71C0A8D5CC36F319F87B7421260F128EFFF75B9A17C2CC7 ######
I/flutter ( 8745): ###### DEBUG Parse blockchainTX list. Cursor: 384695:4BF72317A538FB37F71C0A8D5CC36F319F87B7421260F128EFFF75B9A17C2CC7 ######
Run Code Online (Sandbox Code Playgroud)

请注意,该scrollController函数执行了两次,第一个光标的值相同。然后该parseHistory函数被执行了3次!我刚刚滚动到此处加载 1 页。

我真的不明白这种行为......我已经研究它一周了,如果这个库的开发人员可以向我解释它那就太棒了。

我正在使用该graphql_flutter库的版本 4.0.0-beta.6。


编辑:这是此测试的 UI 关联:在此输入图像描述

nRepository这里的值为3.

mic*_*ize 5

这里的一个问题是您在函数_scrollController.addListener()内调用build,因此每次重建视图时都会添加一个侦听器。fetchMore(opts)这就是为什么每次maxScrollExtent到达时都会触发所有早期调用的原因。

您可以将调用addListener移至更合适的生命周期方法,例如initState,但我实际上建议使用NotificationListener<ScrollUpdateNotification>,它更具声明性,并且可能更适合您当前的代码。

与此无关,您可能想要检查空的“停止”光标,以防止无限的空最后一页请求(尽管如果您的列表可以增长并且您的后端考虑了它,则可能不会)。