How to implement load more data with flutter_bloc without reload every time: I have this:
post_bloc.dart:
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:scroool/post_events.dart';
import 'package:scroool/post_repo.dart';
import 'package:scroool/post_states.dart';
class PostsBloc extends Bloc<PostEvents, PostsStates> {
PostRepo repo;
int page = 1;
ScrollController controller = ScrollController();
PostsBloc(this.repo) : super(PostInitState()){
on<FetchPosts>((event, emit) async{
emit(PostLoadingState());
final posts = await repo.fetchPosts(page);
emit(PostLoadedState(posts: posts));
});
on<LoadMore>((event, emit) async{
if (controller.position.pixels ==
controller.position.maxScrollExtent) {
emit(LoadMoreState());
page ;
final posts = await repo.fetchPosts(page);
emit(PostLoadedState(posts: posts));
// isLoadingMore = false;
} else {
print("not called");
}
});
}
}
And at home.dart:
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:scroool/post_bloc.dart';
import 'package:scroool/post_events.dart';
import 'package:scroool/post_states.dart';
class Scroool extends StatelessWidget {
List posts = [];
@override
Widget build(BuildContext context) {
return Scaffold(
body: BlocConsumer<PostsBloc, PostsStates>(
listener: (context, state){},
builder: (context, state) {
if(state is PostLoadingState) {
return const Center(child: CircularProgressIndicator(),);
} else if(state is PostLoadedState) {
posts = posts state.posts;
return ListView.builder(
controller: context.read<PostsBloc>().controller
..addListener(() => context.read<PostsBloc>().add(LoadMore())),
itemCount: state is LoadMoreState
? posts.length 1 : posts.length ,
itemBuilder: (context, index) {
if(index < posts.length) {
final post = posts[index];
return Card(
child: ListTile(
leading: CircleAvatar(child: Text("${index 1}"),),
title: Text(post['author'].toString()),
subtitle: Text(post['title']['rendered']),
)
);
} else {
return Center(child: CircularProgressIndicator(),);
}
},
);
} else {
return Container();
}
},
)
);
}
}
It is working without any problem, but every time I need to load more is just re-emit the state and display data from beginning, I need just continue with more data not reload and add all data
CodePudding user response:
Change your BLoC state so the parent state will have property posts
. You can set it to empty list for states that do not use it.
abstract class PostState {
final List<Post> posts;
PostState(this.posts);
}
class PostLoadingState extends PostState {
LoadMoreState() : super ([]);
}
class LoadMoreState extends PostState {
LoadMoreState({required List<Post> posts}) : super (posts);
}
class PostLoadedState extends PostState {
PostLoadedState({required List<Post> posts}) : super (posts);
}
Then change your BLoC accordingly:
on<LoadMore>((event, emit) async{
if (controller.position.pixels ==
controller.position.maxScrollExtent) {
emit(LoadMoreState(posts: state.posts));
page ;
final posts = await repo.fetchPosts(page);
emit(PostLoadedState(posts: [...state.posts, ...posts]));
} else {
print("not called");
}
});
In your widget remove the posts
variable and use posts
from bloc's state. Since your parent state has property posts
, you can access posts
for every state, including LoadMoreState
. So change the if condition to return ListView
for all states except PostLoadingState
.
class Scroool extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: BlocConsumer<PostsBloc, PostsStates>(
listener: (context, state){},
builder: (context, state) {
if(state is PostLoadingState) {
return const Center(child: CircularProgressIndicator(),);
} else {
final posts = state.posts;
return ListView.builder(
controller: context.read<PostsBloc>().controller
..addListener(() => context.read<PostsBloc>().add(LoadMore())),
itemCount: state is LoadMoreState
? posts.length 1 : posts.length ,
itemBuilder: (context, index) {
if(index < posts.length) {
final post = posts[index];
return Card(
child: ListTile(
leading: CircleAvatar(child: Text("${index 1}"),),
title: Text(post['author'].toString()),
subtitle: Text(post['title']['rendered']),
)
);
} else {
return Center(child: CircularProgressIndicator(),);
}
},
);
}
},
)
);
}
}