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;
}
}
:hourglass: reproduction needed Priority: Waiting to be assigned