getx
getx copied to clipboard
Prevent rebuild entire SliverGrid on LOAD more data
Describe the bug Load more data, then pass the data to view uses GetX. The App rebuild entire SliverGrid
**Reproduction code
class ProductCategoryController extends BaseController {
final fetchDataState = BaseState();
final GetProductsDataUseCase _getProductsDataUseCase;
ProductCategoryController(this._getProductsDataUseCase);
late RxList<ProductEntity> pEntities;
int firstPage = 1;
RxBool isLoading = true.obs;
RxBool isCompleted = false.obs;
RxInt totalItems = 0.obs;
RxDouble currentPixel = 0.0.obs;
@override
void onInit() async {
super.onInit();
pEntities = <ProductEntity>[].obs;
await getProductData(firstPage);
}
Future<void> getProductData(int startIndex) {
return _getProductsDataUseCase.execute(
observer: Observer(onSubscribe: () {
fetchDataState.onLoading();
}, onSuccess: (data) {
fetchDataState.onSuccess();
isLoading.value = false;
bool isLastPage = data.paging!.lastPage! == data.paging!.currentPage!;
totalItems.value = data.paging!.totalItems!;
if (isLastPage) {
isCompleted.value = true;
}
pEntities.addAll(data.results!);
}, onError: (AppException e) {
isLoading.value = false;
fetchDataState.onError(e.message);
}),
input: PaginateRequest(startIndex, 10),
);
}
Future<void> callRefresh() async {
firstPage = 1;
pEntities.clear();
isCompleted.value = false;
await getProductData(firstPage);
}
Future<void> callLoadmore() async {
if (isLoading.value || isCompleted.value) {
return;
}
isLoading.value = true;
firstPage++;
await getProductData(firstPage);
}
Widget build(BuildContext context) {
Random rnd = Random();
late double minExtent;
late double maxExtent;
minExtent = kToolbarHeight + MediaQuery.paddingOf(context).top;
maxExtent = Platform.isAndroid ? 216 : 256;
bool rowShowSale = false;
ScrollController chilScrollController = ScrollController();
return Scaffold(
extendBodyBehindAppBar: true,
backgroundColor: AppColor.secondaryExtraSoft,
body: AppBarScrollHandler(
minExtent: minExtent,
maxExtent: maxExtent,
controller: chilScrollController,
child: Obx(() => NotificationListener(
onNotification: (ScrollNotification note) {
controller.currentPixel(note.metrics.pixels);
L.info('pixels: ' + note.metrics.pixels.toString());
if (note.metrics.pixels == note.metrics.maxScrollExtent) {
controller.callLoadmore();
}
return true;
},
child: RefreshIndicator(
onRefresh: () {
controller.callRefresh();
return Future<void>.delayed(const Duration(seconds: 1));
},
child: CustomScrollView(
// shrinkWrap: false,
cacheExtent: 200,
controller: chilScrollController,
physics: const BouncingScrollPhysics(
parent: AlwaysScrollableScrollPhysics()),
slivers: [
SliverPersistentHeader(
pinned: true,
delegate: SliverAppBarDelegate(
minExtent: minExtent,
maxExtent: maxExtent,
),
),
SliverPadding(
padding: const EdgeInsets.all(8.0),
sliver: SliverGrid.builder(
addAutomaticKeepAlives: true,
// addAutomaticKeepAlives: false,
// addRepaintBoundaries: false,
// addSemanticIndexes: false,
itemCount: controller.pEntities.length,
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 5.0,
mainAxisSpacing: 5.0,
// mainAxisExtent: 100,
childAspectRatio: 0.5),
itemBuilder: (context, index) {
ProductEntity productEntity =
controller.pEntities[index];
return ProductCard(
// width: 0.25 * MediaQuery.of(context).size.width,
aspectRatio: 1,
no: (index + 1),
sale: rowShowSale,
product: productEntity,
// liveDate: liveDate,
onPress: () {
showModalBottomSheet(
context: context,
builder: (BuildContext context) {
return SizedBox(
height: 200,
child: Center(
child: Column(
mainAxisAlignment:
MainAxisAlignment
.center,
mainAxisSize:
MainAxisSize.min,
children: <Widget>[
const Text(
'Modal BottomSheet'),
ElevatedButton(
child: const Text(
'Close BottomSheet'),
onPressed: () =>
Navigator.pop(
context),
),
],
),
),
);
});
});
})),
SliverToBoxAdapter(
child: controller.isLoading.value
? const Padding(
padding: EdgeInsets.all(8.0),
child: Center(
child: CircularProgressIndicator()),
)
: (controller.pEntities.isEmpty
? const Padding(
padding: EdgeInsets.all(8.0),
child: Center(
child: Text('No record found!'),
),
)
: (controller.isCompleted.value
? const Padding(
padding: EdgeInsets.all(8.0),
child: Center(
child: Text(
"--- Đã tải hết ---",
style: TextStyle(
color: Colors.black38),
)))
: const Padding(
padding: EdgeInsets.all(8.0),
child: Center(
child: Text(
"--- Kéo để tải thêm ---",
style: TextStyle(
color: Colors.black38),
))))),
)
],
))))));
}
Expected behavior Append new item to SliverGrid when loading more data. Previous items are not regenerated.
Screenshots
Flutter Version: 3.19.6
Getx Version: 4.6.5
Describe on which device you found the bug: ios 17, android 24