Flutter and Getx State Management – List View Changes

Issue

Creating one Shopping App using flutter with Getx State Management. I don’t know how to create a controller for each element in the list. So that, any changes in the particular element in the list it will reload only that element not the entire list reload.

enter image description here

If I Clicked "New Order" Container, other Container("Order Confirmed", "Completed") also rebuilds (entire list view rebuilds).

My Model :

import 'package:get/get.dart';

class TabModel {
  late String tabName;
  RxBool isSelected = false.obs;

  TabModel(this.tabName);
}

My Controller :

import 'package:get/get.dart';
import 'package:super_mart_merchant/view/orders/view_models/tab_model.dart';
import 'package:collection/collection.dart';

class TabViewController extends GetxController{
  RxList<TabModel> tabModels = <TabModel>[].obs;
  @override
  void onInit() {
    super.onInit();
    loadVal('New Order',true);
    loadVal('Order Confirmed',false);
    loadVal('Order Declined',false);
    loadVal('Completed',false);
  }

  void loadVal(String name,bool isSelected){
    TabModel tabModel = TabModel(name);
    tabModel.isSelected.value = isSelected;
    tabModels.add(tabModel);
  }

  void onClick(int pos){
    TabModel tabModel =   tabModels[pos];
    if(!tabModel.isSelected.value){
      TabModel? previousTabModel =  tabModels.firstWhereOrNull((element) => element.isSelected.value);
      if(previousTabModel != null){
        previousTabModel.isSelected.value = false;
      }
      tabModel.isSelected.value = true;

    }

  }
}

Binding:

import 'package:get/get.dart';
import 'package:super_mart_merchant/view/orders/controllers/tab_controller.dart';

class TabControllerBinding implements Bindings{
  @override
  void dependencies() {
    Get.lazyPut<TabViewController>(() => TabViewController());

  }
}

View :

class TabView extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return GetX<TabViewController>(
      builder: (TabViewController tabController) {
        print('Object called : ${tabController.toString()}');
        return Container(
          height: 55,
          alignment: Alignment.center,
          child: ListView.builder(
            scrollDirection: Axis.horizontal,
            itemBuilder: (ctx, int index) {
              if (tabController.tabModels[index].isSelected.value) {
                return SelectedOrderStatusComponents(
                    tabController.tabModels[index],
                    index);
              }
              return GestureDetector(
                onTap: (){
                  tabController.onClick(index);
                },
                child: UnSelectedOrderStatusComponents(
                    tabController.tabModels[index],
                    index),
              );
            },
            itemCount: tabController.tabModels.length,
          ),
        );
      },
    );
  }
}

In Provider we have options for this. I don’t how to do that in Getx. Great Thanks!!!.

Solution

This is my first time answering here so I hope it is up to the standard, also not too late for your problems.
For your first problem: wanting to keep each tab from rebuilding after navigate in Tabs. You could convert the Tab widget to Stateful widget and add AutomaticKeepAliveClientMixin to prevent it from rebuilding after navigating. Something like this:

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

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

class _TabViewState extends State<TabView>
    with AutomaticKeepAliveClientMixin {
  @override
  Widget build(BuildContext context) {
    super.build(context);
    return Container();
  }
  
  @override
  bool get wantKeepAlive => true;
}

For your second problem, to just reload the item and not the whole list, you can wrap each item in a Obx or GetBuilder and give it a tag base on the index or id of each item, but I don’t recommend doing this since GetX is quite fast in rebuilding, it only rebuild where changed and having too many GetBuilder in one page can affect performance.

return GestureDetector(
     onTap: (){
          tabController.onClick(index);
     },
     child: GetBuilder<TabViewController>(
          id: "item" + tabController.tabModels[index].id,
          builder: (controller) {
              return UnSelectedOrderStatusComponents(
                   tabController.tabModels[index],
                   index);
          }
     )
);

Answered By – user3676506

Answer Checked By – Robin (FlutterFixes Admin)

Leave a Reply

Your email address will not be published. Required fields are marked *