Home > Net >  StateNotifier not updating inside the data function of FutureProvider in Flutter Riverpod
StateNotifier not updating inside the data function of FutureProvider in Flutter Riverpod

Time:10-12

The StateNotifier with the gender does not update as the dropdown choice changes. I have these providers at the beginning of the file:

class GenderController extends StateNotifier<String>{

  GenderController(String state) : super(state);
}

final profileProvider = FutureProvider.autoDispose((ref) {
  final details = ref.watch(authToken);
  var data = API().staffProfile(token: details['token'], staffID: details['ID']);
  return data;
});

final gender = StateNotifierProvider.autoDispose((ref) => GenderController(""));

And this is what the build method looks like in a ConsumerWidget:

 Widget build(BuildContext context, WidgetRef ref) {
    var dropdownValue = ref.watch(gender);
    final details = ref.watch(profileProvider);

return details.when(
      data: (data){
       
        dropdownValue = data['gender'];

        // show the form with the info
        return Padding(
          padding: const EdgeInsets.all(8.0),
          child: Form(
              key: formKey,
              child: Column(
                children: [
                  DropdownButton2(
                      isExpanded: true,
                      underline: Container(
                        color: kDarkGrey,
                        height: 1.0,
                      ),
                      buttonPadding: const EdgeInsets.symmetric(vertical: 10.0),
                      hint: const CustomText(
                        text: "Gender",
                        fontSize: 16.0,
                        color: kBlack,
                      ),
                      items: genders
                          .map((item) => DropdownMenuItem<String>(
                        value: item,
                        child: Text(
                          item,
                          style: const TextStyle(
                            fontSize: 16,
                            color: kBlack,
                          ),
                          overflow: TextOverflow.ellipsis,
                        ),
                      ))
                          .toList(),
                      value: dropdownValue == "" ? null : dropdownValue.toString(),
                      onChanged: (value) {
                        ref.watch(gender.notifier).state =  value!;
                      }
                  ),
                ],
              )
          ),
        );
      },
      error: (err, _){
        debugPrint(_.toString());
        return const Center(
          child: CustomText(
            text: "Error getting profile",
          ),
        );
      },
      loading: () => Center(
        child: CircularProgressIndicator(
          color: kPrimary,
        ),
      )
    );
}

I have also tried making the data type of the dropdownValue to be final and then assigning the data to it as ref.watch(gender.notifier).state = data['gender']; but that resulted in a "At least listener of the StateNotifier Instance of 'GenderController' threw an exception when the notifier tried to update its state." error. Please help.

CodePudding user response:

In callbacks, you must call ref.read

ref.read(gender.notifier).state = data['gender'];

CodePudding user response:

I figured it out. I initialised the dropdown before calling the details.when like this:

DropdownButton2 dropdown = DropdownButton2(
        isExpanded: true,
        underline: Container(
          color: kDarkGrey,
          height: 1.0,
        ),
        buttonPadding: const EdgeInsets.symmetric(vertical: 10.0),
        hint: const CustomText(
          text: "Gender",
          fontSize: 16.0,
          color: kBlack,
        ),
        items: genders
            .map((item) => DropdownMenuItem<String>(
          value: item,
          child: Text(
            item,
            style: const TextStyle(
              fontSize: 16,
              color: kBlack,
            ),
            overflow: TextOverflow.ellipsis,
          ),
        ))
            .toList(),
        value: dropdownValue == "" ? null : dropdownValue.toString(),
        onChanged: (value) {
          ref.read(gender.notifier).state =  value!;
        }
    );

And then I updated the StateNotifier after the data was returned in the FutureProvider like so:

final profileProvider = FutureProvider.autoDispose((ref) async {
  final details = ref.watch(authToken);
  var data = await API().staffProfile(token: details['token'], staffID: details['ID']);
  ref.read(gender.notifier).state = data['gender'];
  return data;
});

Everything works fine now, and as it should.

  • Related