getx icon indicating copy to clipboard operation
getx copied to clipboard

Prevent rebuild entire SliverGrid on LOAD more data

Open canhbd opened this issue 1 year ago • 0 comments

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 prevent-rebuild-SliverGrid-on-reload

Flutter Version: 3.19.6

Getx Version: 4.6.5

Describe on which device you found the bug: ios 17, android 24

canhbd avatar Jun 13 '24 09:06 canhbd