Search code examples
flutterflutter-getx

change the value in the list with getx, the value is updated, but the screen does not rerender


When i change the value in the list with getx, the value is updated, but the screen does not rerender.

i use GetBuilder because wrapping with obx gives an error.

But it still doesn't work where am I making a mistake

my controller:

 RxList<NotificationControl> notificationControlList =
      <NotificationControl>[].obs;

  void checkBoxChange(bool value, int index) {
    notificationControlList[index].isChecked = value;
    update();
  }

my view:

class NotificationCheckbox extends StatelessWidget {
  NotificationCheckbox({
    Key? key,
    required this.index,
  }) : super(key: key);

  final int index;
  
  @override
  Widget build(BuildContext context) {
    return GetBuilder<NotificationController>(
      id: "notification-cbx",
      // autoRemove: false, 
      // init: NotificationController(),
      builder: (logic) {
        return Checkbox(
          value: logic.notificationControlList[index].isChecked,
          onChanged: (bool? value) {
            logic.checkBoxChange(value ?? false, index);
          },
        );
      },
    );
  }
}

i use GetBuilder because wrapping with obx gives an error:

  [Get] the improper use of a GetX has been detected. 
  You should only use GetX or Obx for the specific widget that will be updated.
  If you are seeing this error, you probably did not insert any observable variables into GetX/Obx 
  or insert them outside the scope that GetX considers suitable for an update 
  (example: GetX => HeavyWidget => variableObservable).
  If you need to update a parent widget and a child widget, wrap each one in an Obx/GetX.
  

Solution

  • The problem is that the contents of notificationControlList are being mutated outside the scope of GetX observers. The list doesn't know the items are being mutated. The way to make it work is to assign the changed item to the list in the same index. It's going to be like the below code snippet:

    class NotificationController extends GetxController {
      RxList<NotificationControl> notificationControlList =
          <NotificationControl>[].obs;
    
      void checkBoxChange(bool value, int index) {
        notificationControlList[index].isChecked = value;
        notificationControlList[index] = notificationControlList[index];   // <- Just assign
        update();
      }
    }
    

    A better alternative though is to make NotificationControl immutable so this error never happens again. Make it like the following (assuming the properties title and isChecked):

    class NotificationControl {
      final String title;
      final bool isChecked;
      const NotificationControl({required this.title, required this.isChecked});
    
      NotificationControl copyWith({bool? isChecked, String? title}) {
        return NotificationControl(
          title: title ?? this.title,
          isChecked: isChecked ?? this.isChecked,
        );
      }
    }
    

    The copyWith serves to clone the NotificationControl changing just the needed properties. The controller now looks like this:

    class NotificationController extends GetxController {
      RxList<NotificationControl> notificationControlList =
          <NotificationControl>[].obs;
    
      void checkBoxChange(bool value, int index) {
        notificationControlList[index] =
            notificationControlList[index].copyWith(isChecked: value);
        update();
      }
    }