graphql-flutter icon indicating copy to clipboard operation
graphql-flutter copied to clipboard

fetchMore and refetch don't fetch information at all

Open businessAccountFlutter opened this issue 2 years ago • 12 comments

Just like in the title, I was wondering how to use fetchMore. I was trying a lot of different technics (like trying to do it with refetch) but I am not moving forward with this at all, it just doesn't pull the new information. Code below is what I'm stuck with now. This is meant to be my pagination attempt for my work project. I feel like I cannot find too much information on how to get this to work - it doesn't fetchMore results, the result.data doesn't get updated with newly fetched data - basically it doesn't work. Also, I don't really understand how to get the new Map (I would love for the new results to be merged into the old map) as a variable after previous result and new result are merged together - I would like it to be hopefully a smooth experience and for the data to show up right on the bottom and for the user to not be transported to the top of the list.

class Page extends StatefulWidget {
  const Page({Key? key}) : super(key: key);

  @override
  PageState createState() => PageState();
}

var howManyToFetch = 3;
var offset = 0;
List repositories = [];
bool refetched = false;

late String readRepositories = '''
          query MyQuery {
(*branch element*)(first: $howManyToFetch, offset: $offset, orderBy: "-published") {
(*I cannot show you the rest of the query*)
  ''';

class PageState extends State<Page> {

  var hasMore = true;
  final controller = ScrollController();

  Future fetch() async {
    if (hasMore) {
      offset = offset+3;
      print("How many to fetch?"+howManyToFetch.toString());
      refetched = true;
      setState(() {});
    } else {
      setState(() {});
    }
  }

  @override
  void initState() {
    super.initState();
    controller.addListener(() {
      if (controller.position.maxScrollExtent == controller.offset) {
        fetch();
      }
    });
  }

  @override
  void dispose() {
    controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(`
        backgroundColor: Colors.white60,
        appBar: PreferredSize(
          preferredSize:
          Size.fromHeight(MediaQuery.of(context).size.height * 0.07),
          child: Stack(
            children: [
              AppBar(),
              Container(
                alignment: Alignment.bottomCenter,
                child: Image.asset(
                  assetName,
                  fit: BoxFit.contain,
                  height: MediaQuery.of(context).size.height * 0.07,
                ),
              )
            ],
          ),
        ),

       body: Query(
          options: QueryOptions(document: gql(readRepositories)),
          builder:
              (QueryResult result, {
            VoidCallback? refetch,
            FetchMore? fetchMore,
          }) {
            if (result.hasException) {
              return Text(result.exception.toString());
            }

            if (result.isLoading) {
              return const Center(
                child: CircularProgressIndicator(),
              );
            }

            if (repositories.isEmpty) {
              repositories = result.data?(*Rest of the path to edges*);
              print("Empty "+(result.data?(*Rest of the path to edges*).length).toString());
            }
            else {
              if (refetched) {
                refetch!();
                fetchMore!(FetchMoreOptions(updateQuery: (prev, fetched) => prev = deeplyMergeLeft(
                  [prev, fetched],
                ), variables: {"offset":offset, "first":howManyToFetch}));
                print("Not empty "+(result.data?[(*Rest of the path to edges*).length).toString());
                List repositories1 = result.data?(*Rest of the path to edges*);
                print(repositories1.length);
                // List newRepositories = result.data?(*Rest of the path to edges*);
                // for (int i=0;i<newRepositories.length;i++) {
                //   repositories.add(newRepositories[i]);
                // }
                refetched = false;
              }
            }

            hasMore = (result.data?(*Rest of the path to hasNextPage*));

            if (repositories == null) {
              return const Text('No repositories');
            }

            return ListView.builder(
              controller: controller,
                itemCount: repositories.length+1,
                itemBuilder: (context, index) {
                  if (index < repositories.length){
                    final repository = repositories[index];

(*List elements' variables*)

                    (*Component for creating list elements*) {
                      onTap: () {
                        Navigator.push(
                          context,
                          MaterialPageRoute(
                              builder: (context) => (*Builder function*)
                        );
                      },
                    );
                  } else {
                    return Padding(padding: const EdgeInsets.only(top: 10.0, bottom: 10.0), child: Center(child: hasMore ? const CircularProgressIndicator() : const Text("No more information", style: TextStyle(color: Colors.grey),),),);
                  }
                });
          },
        )
    );
  }
}

UPDATE It seems as if it couldn't take new variable values or even the query itself because when I wanted to check if variables update they did but the result was still the same, but after I added a part where if it refetches/fetches more it has to clear the result data from the map and it now shows null, doesn't add new data to it.

The code is now (I am constantly commenting and uncommenting different parts of it):

if (repositories.isEmpty) {
              repositories = result.data?(*path*)?['edges'];
              print("Empty "+(result.data?(*path*)?['edges'].length).toString());
            }
            else {
              if (refetched) {
                result.data?.clear();
                refetch!();
                // var opts = FetchMoreOptions.partialUpdater((prev, fetched) => deeplyMergeLeft([prev, fetched]));
                // fetchMore!(FetchMoreOptions(updateQuery: opts, variables: {"offset": offset, "first":howManyToFetch}));
                // fetchMore!(FetchMoreOptions(updateQuery: (prev, fetched) => deeplyMergeLeft(
                //   [prev, fetched],
                //   ), variables: {"offset":offset, "first":howManyToFetch}));
                print("offset "+offset.toString());
                print("How many to fetch? "+howManyToFetch.toString());
                print("Not empty "+(result.data?(*path*).length).toString());
                // List newRepositories = result.data?(*path*);
                // for (int i=0;i<newRepositories.length;i++) {
                //   repositories.add(newRepositories[i]);
                // }
                refetched = false;
              }
            }

businessAccountFlutter avatar Aug 12 '22 11:08 businessAccountFlutter

TBH I'm having a hard time following your question here.

Are you wondering how you can merge the result? - Then look at the updateQuery: argument to your FetchOptions. The deeplyMergeLeft function doesn't concat arrays so you'll need to implement your own logic.

budde377 avatar Aug 12 '22 19:08 budde377

I am also having serious issue while using the fetchMore method and there are scarce resources on the web to help with this. I'll appreciate it if a clearer example of how this method can be used is provided.

majorsigma avatar Aug 15 '22 05:08 majorsigma

@majorsigma please describe your issue in more detail and we can help.

budde377 avatar Aug 15 '22 06:08 budde377

@majorsigma please describe your issue in more detail and we can help.

Here is a method I created to fetch latest ads

Future<QueryResult<dynamic>> fetchMoreLatestAds({
   int? adLocationId,
   String? sortOrder,
   String? adCondition,
   String? adType,
   int? limit,
   int? offset,
 }) async {
   FetchMoreOptions fetchMoreOptions = FetchMoreOptions(
       document: gql(
"""
query FetchLatestAds(
   ${sortOrder == null ? '' : '\$sortOrder: order_by,'}
   ${adCondition == null ? '' : '\$adCondition: String,'}
   ${adType == null ? '' : '\$adType: String,'}
   ${adLocationId == null ? '' : '\$adLocationId: Int,'}
   ${limit == null ? '' : '\$limit: Int,'}
   ${offset == null ? '' : '\$offset: Int,'}
) {
 Adverts(
   where: {
     status: {_eq: LIVE}
     condition: ${adCondition == null ? '{}' : '{_eq: \$adCondition}'},
     type: ${adType == null ? '{}' : '{_eq: \$adType}'}
     local_government: {
       id: ${adLocationId == null ? '{}' : '{_eq: \$adLocationId}'}
     }
   },
  ${sortOrder == null ? '' : 'order_by: {createdAt: $sortOrder}'}
  ${limit == null ? '' : 'limit: \$limit'}
  ${offset == null ? '' : 'offset: \$offset'}
 ) {
   promotion {
     status
     expiry
     transaction {
       promotion_package {
         name
         type
       }
     }
   }
   ID
   category_id
   condition
   createdAt
   discountPrice
   isNegotiable
   name_of_store
   priceAndOthers {
     ads_id
     discountPrice
     id
     jobMaxSalary
     jobRole
     jobSalary
     maxPrice
     jobType
     rentPeriod
     reservePrice
     standardPrice
     startPrice
     yearsOfExperience
   }
   user {
     userProfiles {
       first_name
       last_name
       display_name
     }
   }
   standardPrice
   state
   status
   sub_category_id
   title
   termsAndCondition
   type
   user_id
   phone
   LGA
   adds_category {
     title
   }
   Images {
     thumbnail
   }
   AddsReviews {
     id
   }
   views {
     id
   }
   ads_state {
     id
     name
   }
   local_government {
     id
     name
   }
   AddsReviews_aggregate {
     aggregate {
       avg {
         rating
       }
     }
   }
 }
}
"""
),
       variables: determineQueryVariablesForLatestAdsPage(
         sortOrder: sortOrder,
         adCondition: adCondition,
         adLocationId: adLocationId,
         adType: adType,
         limit: limit,
       ),
       updateQuery: (
         Map<String, dynamic>? previousResultData,
         Map<String, dynamic>? fetchMoreResultData,
       ) {
         final List<dynamic> adverts = [
           ...previousResultData?['Adverts'],
           ...fetchMoreResultData?['Adverts'],
         ];
       
        _logger.d("Fetched adverts: $adverts");
         return {"Adverts": adverts};
       });

Is the way I implemented it okay?

majorsigma avatar Aug 15 '22 12:08 majorsigma

TBH I'm having a hard time following your question here.

Are you wondering how you can merge the result? - Then look at the updateQuery: argument to your FetchOptions. The deeplyMergeLeft function doesn't concat arrays so you'll need to implement your own logic.

Yes but there is a more important issue which is that neither fetchMore nor refetch work - fetchMore doesn't fetch any data as to my understanding while refetch doesn't refresh the values of variables used in the query.

Could you help me understand what I'm doing wrong? As @majorsigma said there is not enough information on the topic of fetchMore.

Update: I've now implemented something that I thought might work but it still didn't. Here's the code and debug response: Zrzut ekranu 2022-08-16 o 10 36 07

businessAccountFlutter avatar Aug 16 '22 06:08 businessAccountFlutter

Help me help you. I understand that it's frustrating that you don't feel that this works and is properly documented. We're always open to PRs! For me to understand your question and help you, can you please write a minimal reproducible example with an explanation on what you're expecting and what you're seeing. I can't reproduce screenshots.

budde377 avatar Aug 16 '22 09:08 budde377

Help me help you. I understand that it's frustrating that you don't feel that this works and is properly documented. We're always open to PRs! For me to understand your question and help you, can you please write a minimal reproducible example with an explanation on what you're expecting and what you're seeing. I can't reproduce screenshots.

My file is responsible for showing cards with data fetched from database. Here is a fragment of the Scaffold body with Query widget.

body: Query(
          options: QueryOptions(document: gql(readRepositories)),
          builder:
              (QueryResult result, {
            VoidCallback? refetch,
            FetchMore? fetchMore,
          }) {
            if (result.hasException) {
              return Text(result.exception.toString());
            }

            if (result.isLoading) {
              return const Center(
                child: CircularProgressIndicator(),
              );
            }

            if (repositories.isEmpty) {
              repositories = result.data?['allNews']?['edges'];
              print("Empty "+(result.data?['allNews']?['edges'].length).toString());
            }
            else {
              if (refetched) {

                //result.data?.clear();
                //refetch!();
                Map<String,dynamic> newMap = {};
                // var opts = FetchMoreOptions.partialUpdater((prev, fetched) => newMap = {
                //   ...?prev,
                //   ...?fetched,
                // });
                fetchMore!(FetchMoreOptions(updateQuery: (prev, fetched) => newMap = {
                  ...?prev,
                  ...?fetched,
                }, variables: {"offset": offset, "first":howManyToFetch}));
                // fetchMore!(FetchMoreOptions(updateQuery: (prev, fetched) => deeplyMergeLeft(
                //  [prev, fetched],
                //  ), variables: {"offset":offset, "first":howManyToFetch}));
                print("offset "+offset.toString());
                print("How many to fetch? "+howManyToFetch.toString());
                print("Not empty "+(newMap.length).toString());
                List newRepositories = result.data?['allNews']?['edges'];
                for (int i=0;i<newRepositories.length;i++) {
                  repositories.add(newRepositories[i]);
                }
                refetched = false;
              }
            }

If you need me to I can send you the whole code that is in the dart file.

businessAccountFlutter avatar Aug 16 '22 09:08 businessAccountFlutter

You should be able to reproduce your problem in a clean repository or a simple query, we are preparing a debug API that you can do for this job https://api.chat.graphql-flutter.dev/graphql

P.S: This process is always required to give us the possibility to debug it with a monkey example, and debug it. Most of the issue can be cause from other stuff that is going on your code, so it is useful also to you this to avoid waste time to catch bugs that may not exit.

Have fun!

Sorry if I jump in the conversation

vincenzopalazzo avatar Aug 16 '22 10:08 vincenzopalazzo

You should be able to reproduce your problem in a clean repository or a simple query, we are preparing a debug API that you can do for this job https://api.chat.graphql-flutter.dev/graphql

P.S: This process is always required to give us the possibility to debug it with a monkey example, and debug it. Most of the issue can be cause from other stuff that is going on your code, so it is useful also to you this to avoid waste time to catch bugs that may not exit.

Have fun!

Sorry if I jump in the conversation

Ok, I'll post the whole code if it helps but I'm not sure if it does. I don't really know how to give you the example so you could reproduce it.

import 'package:flutter/material.dart';
import 'package:graphql_flutter/graphql_flutter.dart';
import 'package:graphql/src/utilities/helpers.dart';
import 'package:intl/intl.dart';

import '../tile_widget/article_tile_big_photo.dart';
import 'informacje_page_inside.dart';


class InformacjePage extends StatefulWidget {
  const InformacjePage({Key? key}) : super(key: key);

  @override
  _InformacjePageState createState() => _InformacjePageState();
}

var howManyToFetch = 3;
var offset = 0;
List repositories = [];
bool refetched = false;

late String readRepositories = '''
          query MyQuery {
            allNews(first: $howManyToFetch, offset: $offset, orderBy: "-published") {
              edges {
                node {
                  name
                  id
                  published
                  newsPhotos {
                    edges {
                      node {
                        file
                      }
                    }
                  }
                }
              }
              pageInfo {
                hasNextPage
              }
            }
          }
  ''';

class _InformacjePageState extends State<InformacjePage> {

  var korekta = 0;

  var hasMore = true;
  final controller = ScrollController();

  Future fetch() async {
    if (hasMore) {
      offset = offset+3;
      refetched = true;
      setState(() {});
    } else {
      setState(() {});
    }
  }

  @override
  void initState() {
    super.initState();
    controller.addListener(() {
      if (controller.position.maxScrollExtent == controller.offset) {
        fetch();
      }
    });
  }

  @override
  void dispose() {
    controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        backgroundColor: Colors.white60,
        appBar: PreferredSize(
          preferredSize:
          Size.fromHeight(MediaQuery.of(context).size.height * 0.07),
          child: Stack(
            children: [
              AppBar(),
              Container(
                alignment: Alignment.bottomCenter,
                child: Image.asset(
                  'assets/logo_herb_poziom_sww_kolor.png',
                  fit: BoxFit.contain,
                  height: MediaQuery.of(context).size.height * 0.07,
                ),
              )
            ],
          ),
        ),
        body: Query(
          options: QueryOptions(document: gql(readRepositories)),
          builder:
              (QueryResult result, {
            VoidCallback? refetch,
            FetchMore? fetchMore,
          }) {
            if (result.hasException) {
              return Text(result.exception.toString());
            }

            if (result.isLoading) {
              return const Center(
                child: CircularProgressIndicator(),
              );
            }

            if (repositories.isEmpty) {
              repositories = result.data?['allNews']?['edges'];
              print("Empty "+(result.data?['allNews']?['edges'].length).toString());
            }
            else {
              if (refetched) {

                //result.data?.clear();
                //refetch!();
                Map<String,dynamic> newMap = {};
                // var opts = FetchMoreOptions.partialUpdater((prev, fetched) => newMap = {
                //   ...?prev,
                //   ...?fetched,
                // });
                fetchMore!(FetchMoreOptions(updateQuery: (prev, fetched) => newMap = {
                  ...?prev,
                  ...?fetched,
                }, variables: {"offset": offset, "first":howManyToFetch}));
                // fetchMore!(FetchMoreOptions(updateQuery: (prev, fetched) => deeplyMergeLeft(
                //  [prev, fetched],
                //  ), variables: {"offset":offset, "first":howManyToFetch}));
                print("offset "+offset.toString());
                print("How many to fetch? "+howManyToFetch.toString());
                print("Not empty "+(newMap.length).toString());
                List newRepositories = result.data?['allNews']?['edges'];
                for (int i=0;i<newRepositories.length;i++) {
                  repositories.add(newRepositories[i]);
                }
                refetched = false;
              }
            }

            hasMore = (result.data?['allNews']?['pageInfo']?['hasNextPage']);

            if (repositories == null) {
              return const Text('No repositories');
            }

            return ListView.builder(
              controller: controller,
                itemCount: repositories.length+1,
                itemBuilder: (context, index) {
                  if (index < repositories.length){
                    final repository = repositories[index];

                    var title = (repository['node']?['name'] ?? "Brak danych");

                    final List photos =
                        repository['node']?['newsPhotos']?['edges'];
                    var photo = "Brak zdjecia";
                    if (photos.isNotEmpty) {
                      photo = (photos[0]?['node']?['file'] ?? "Brak zdjecia");
                    }
                    var photoLink =
                        "http://ns31200045.ip-51-83-143.eu:25001/media/" +
                            photo;

                    DateTime dt =
                        DateTime.parse(repository['node']?['published']);
                    final createdDay =
                        DateFormat('dd.MM.yyyy, kk:mm').format(dt);

                    var city = "";

                    if (index > 3) {
                      korekta = index ~/ 4;
                    } else {
                      korekta = 0;
                    }
                    var newColor = index - korekta * 4;

                    return ArticleTileBigPhoto(
                      thumbnail: NetworkImage(photoLink),
                      title: title,
                      publishDate: createdDay,
                      city: city,
                      colorInt: newColor,
                      onTap: () {
                        Navigator.push(
                          context,
                          MaterialPageRoute(
                              builder: (context) => ArticlePageInside(
                                  id: repository['node']?['id'], name: title,photoLink: photoLink,),),
                        );
                      },
                    );
                  } else {
                    return Padding(padding: const EdgeInsets.only(top: 10.0, bottom: 10.0), child: Center(child: hasMore ? const CircularProgressIndicator() : const Text("Brak informacji do pobrania", style: TextStyle(color: Colors.grey),),),);
                  }
                });
          },
        )
    );
  }
}

businessAccountFlutter avatar Aug 16 '22 10:08 businessAccountFlutter

Cheers, now please explain what you're seeing and what you're expecting in a way you'd explain it to a junior dev on your team

budde377 avatar Aug 16 '22 11:08 budde377

Cheers, now please explain what you're seeing and what you're expecting in a way you'd explain it to a junior dev on your team

Well, what I'm seeing is something like that:

Zrzut ekranu 2022-08-16 o 13 14 03

The problem is that it seems like the fetchMore function doesn't work or I simply cannot use it. After it's called my new results (if they even exist because I cannot work out whether fetchMore works or not but it may work because when it runs it reloads the list) are not merged into one map with previous results which is shown by the "Not empty 0" debug message which is responsible for showing merged results map. What I need is to update my list of news objects (being title, photo and publication date) with newly downloaded data, for now 3 at a time. I am trying to use pagination because I simply don't want to download all the data at the same time. I would like it to also not take the user to the top of the list when it fetches more data.

I've tried to use result.data after refetch but it didn't work, especially after clear() the result.data. I also tried updating the list I'm using to create the ListView but it only caused a flickering effect.

I hope I explained it good enough. Sorry if anything is unclear.

businessAccountFlutter avatar Aug 16 '22 11:08 businessAccountFlutter

I've changed the fetchMore part in the Query builder to: Zrzut ekranu 2022-08-17 o 08 33 57

The result I'm getting is all the same results as I got previously so prev = fetched even tho I have the variables listed. And also, the fetchMore function is done after all the other things in the function placed after it. Here it is represented by debug and screenshot from my app which already displays the data of the first query but fetch downloaded the same data again against the variables being prepared to download completely new data. Zrzut ekranu 2022-08-17 o 08 33 13

Update: It seems to me like the fetchMore doesn't consider the variables I pass. How to get them to work? Here is a reference picture of what the debug shows after printing both previous and newly fetched data: Zrzut ekranu 2022-08-17 o 11 14 33

Here is the length of both results: Zrzut ekranu 2022-08-17 o 11 19 27

businessAccountFlutter avatar Aug 17 '22 06:08 businessAccountFlutter

Alright, so I think I know what's going on here. It's pretty hard to follow your code but I understand that you're having problems propagating your variables because this is how you build your query:

late String readRepositories = '''
          query MyQuery {
            allNews(first: $howManyToFetch, offset: $offset, orderBy: "-published") {
              edges {
                node {
                  name
                  id
                  published
                  newsPhotos {
                    edges {
                      node {
                        file
                      }
                    }
                  }
                }
              }
              pageInfo {
                hasNextPage
              }
            }
          }
  ''';

Your query should never change. It should be constant. So injecting your variables like this will fail.

const String readRepositories = r'''
          query MyQuery($first: Int!, $offset: Int!) {
            allNews(first: $first, offset: $offset, orderBy: "-published") {
              edges {
                node {
                  name
                  id
                  published
                  newsPhotos {
                    edges {
                      node {
                        file
                      }
                    }
                  }
                }
              }
              pageInfo {
                hasNextPage
              }
            }
          }
  ''';

now you can correctly pass new variables when calling fetch more.

budde377 avatar Aug 23 '22 20:08 budde377

@budde377 it still doesn't work

(first: $first, offset: $offset, orderBy: "-published")

I get an error that constant variables can't be assigned a value. I know that but I need to assign offset with new value for it to change. Also, this: Zrzut ekranu 2022-08-24 o 12 24 50

businessAccountFlutter avatar Aug 24 '22 10:08 businessAccountFlutter

you are missing the r in front of the string, otherwise this error make no sense to me, the query look sane

vincenzopalazzo avatar Aug 24 '22 10:08 vincenzopalazzo

I've change code to:

int first = 3;
int offset = 0;
List<dynamic> repositories = [];
bool refetched = false;

const String readRepositories = r'''
          query MyQuery($first: Int!, $offset: Int!) {
            allNews(first: $first, offset: $offset, orderBy: "-published") {
              edges {
                node {
                  name
                  id
                  published
                  newsPhotos {
                    edges {
                      node {
                        file
                      }
                    }
                  }
                }
              }
              pageInfo {
                hasNextPage
              }
            }
          }
  ''';

Now I'm getting this error: Zrzut ekranu 2022-08-24 o 12 33 38

businessAccountFlutter avatar Aug 24 '22 10:08 businessAccountFlutter

The error states that you're missing a variable. Check that you're providing the variable in your query

budde377 avatar Aug 24 '22 10:08 budde377

The error states that you're missing a variable. Check that you're providing the variable in your query

Ok, sorry, it was my mistake. Thank you, everythings working. Still, don't really know how to connect both results into one.

businessAccountFlutter avatar Aug 24 '22 10:08 businessAccountFlutter

That depends on your use case. You have the new and the old data and you need to return whatever you expect to be the result.

budde377 avatar Aug 24 '22 11:08 budde377

That depends on your use case. You have the new and the old data and you need to return whatever you expect to be the result.

Ok, somehow I understood how to do this. Could you please tell me how can I prevent the app from going to the top of my ListView after fetchMore?

businessAccountFlutter avatar Aug 24 '22 11:08 businessAccountFlutter

You mean scrolling to the top?

budde377 avatar Aug 24 '22 11:08 budde377

You mean scrolling to the top?

Right now when my app fetches more data it automatically scrolls to the top by itself. What I would like is for it to stay in the same place the user scrolled to.

businessAccountFlutter avatar Aug 24 '22 11:08 businessAccountFlutter

I can't help you with this because it's highly dependent on your setup and out of scope of this library, I.e. the behaviour would probably be the same if you had any other method of fetching data.

Take a look at scroll controllers and scroll behaviour of your widget? I suspect that you're not storing scroll state in the shape of a scroll controller outside of your build method and thus any re build of your widget will yield a new instance of the scrollable widget being mounted and thus reset. Maybe you can solve this by adding a key to the scrollable view or wrap the query widget inside the scroll view.

budde377 avatar Aug 24 '22 11:08 budde377

I can't help you with this because it's highly dependent on your setup and out of scope of this library, I.e. the behaviour would probably be the same if you had any other method of fetching data.

Take a look at scroll controllers and scroll behaviour of your widget? I suspect that you're not storing scroll state in the shape of a scroll controller outside of your build method and thus any re build of your widget will yield a new instance of the scrollable widget being mounted and thus reset. Maybe you can solve this by adding a key to the scrollable view or wrap the query widget inside the scroll view.

Oh, ok. Thank you so much for all your help!

businessAccountFlutter avatar Aug 24 '22 13:08 businessAccountFlutter

No worries. You can also try and reach out on our discord (link should be in the readme) for quicker answers from the whole community

budde377 avatar Aug 24 '22 13:08 budde377