Search code examples
flutterflutter-getx

Can't update widget data using Getx controller


Data inside widgets do not update.

Following best practice for reusing the code of widgets. I have DashboardScreen and DashboardScreenController, the code provided below:

Dashboard Screen:

class DashboardScreen extends StatelessWidget {
  DashboardScreen({Key? key}) : super(key: key);

  final DashboardController controller = Get.find();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      key: controller.scaffoldKey,
      body: _buildProfile(data: controller.getProfil()),
  }

  Widget _buildProfile({required Profile data}) {
    return Padding(
      padding: const EdgeInsets.symmetric(horizontal: kSpacing),
      child: _ProfilTile(
        data: data,
        onPressedLogOut: () {
          controller.logoutUser();
        },
      ),
    );
  }

}

Dashboard Controller:

class DashboardController extends GetxController {
  final scaffoldKey = GlobalKey<ScaffoldState>();

  // for handling authenticaion
  final AuthService _authService = Get.find();
  final _localSecureStorage = Get.find<LocalSecureStorage>();

  Rx<User?> currentUser = null.obs;

  @override
  void onInit() {
    assignCurrentUser();
    super.onInit();
  }

  void assignCurrentUser() async {
    User? secureData = await _localSecureStorage.getUser;
    currentUser.update((currentUser) => currentUser = secureData);
  }

  // Data
  Profile getProfil() {
    return Profile(
      photo: const AssetImage(ImageRasterPath.avatar1),
      name: currentUser.value != null
          ? currentUser.value!.username.toString()
          : "Loading..",
      email: currentUser.value != null
          ? currentUser.value!.email.toString()
          : "Loading..",
    );
  }

and the reusable piece is the profile widget:

class _ProfilTile extends StatelessWidget {
  const _ProfilTile(
      {required this.data, required this.onPressedLogOut, Key? key})
      : super(key: key);

  final Profile data;
  final Function() onPressedLogOut;

  @override
  Widget build(BuildContext context) {
    return ListTile(
      title: Text(data.name),
      subtitle: Text(data.email),
    );
  }
}

I've tried:

  1. just use User? currentUser instead of using 'Rx<User?> currentUser' but this isn't healping to update UI, only works after hot reload
  2. tried to use Obx() widget in all possible ways by
  • refactoring _buildProfile(data: controller.getProfil()) in dashboard
  • refactoring ListTile widget in _ProfilTile
  • refactoring each Text() independently in _ProfilTile all gives me an error

improper use of a GetX has been detected. using bottomNavigationBar

  1. Tried to use function update() and refresh() inside controller in the assignCurrentUser function

still have same issue after all. the flow of my app is that I get the user from my secure local storage by using await and update user data in controller and updated data in screen by passing it to widget _ProfileTile


Solution

  • first of all, you need to wrap widgets that need to be updated inside an Obx widget.

    Dashbord Screen:

    class DashboardScreen extends StatelessWidget {
      DashboardScreen({Key? key}) : super(key: key);
    
      final DashboardController controller = Get.find();
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          key: controller.scaffoldKey,
          body: Obx(() => _buildProfile(data: controller.getProfil())),
      }
    
      ...
    }
    

    Then inside the DashboardController you can update the currentUser value this way:

    Dashboard Controller:

    class DashboardController extends GetxController {
    
      final Rx<User?> currentUser = Rx<User?>(null);
      ...
    
      void assignCurrentUser() async {
        User? secureData = await _localSecureStorage.getUser;
        currentUser.value = secureData;
      }
    
     ...
    }