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.