I have built this riverpod state:
import "package:riverpod_annotation/riverpod_annotation.dart";
part "form_state.g.dart";
@riverpod
class FormState extends _$FormState {
@override
List<String?> build() {
ref.listenSelf((previous, next) {
log("previous: $previous, next: $next", name: "FORMSTATE 0");
});
return List.filled(10, null);
}
void change(int index, String value) {
log("change: $index, value: $value", name: "FORMSTATE 1");
state = [
...state.sublist(0, index),
value,
...state.sublist(index + 1),
];
}
}
On my Widget, I have a list of TextField
as Below:
class DummyPage extends ConsumerStatefulWidget {
const DummyPage({super.key});
@override
ConsumerState<DummyPage> createState() =>
_DummyPageState();
}
class _DummyPageState extends ConsumerState<DummyPage> {
final List<TextEditingController> _controllers =
List.generate(10.length, (index) => TextEditingController());
@override
void initState() {
final form = ref.read(formStateProvider);
for (var i = 0; i < _controllers.length; i++) {
_controllers[i].text = form[i] ?? "";
}
super.initState();
}
@override
void dispose() {
for (var i = 0; i < _controllers.length; i++) {
_controllers[i].dispose();
}
super.dispose();
}
@override
Widget build(context) {
return Column(children: [
...List.generate(
_controllers.length,
(index) => TextField(
controller: _controllers[index],
onChanged: (val) {
ref.read(formStateProvider.notifier).change(index, val);
}
)
])
}
The current condition is every time onChanged
is called, it always resets the value as below:
[FORMSTATE 0] previous: null, next: [null, null, null, null, null, null]
[FORMSTATE 1] change: 0, value: 2
[FORMSTATE 0] previous: [null, null, null, null, null, null], next: [2, null, null, null, null, null]
[FORMSTATE 0] previous: null, next: [null, null, null, null, null, null]
[FORMSTATE 1] change: 1, value: 3
[FORMSTATE 0] previous: [null, null, null, null, null, null], next: [null, 3, null, null, null, null]
[FORMSTATE 0] previous: null, next: [null, null, null, null, null, null]
[FORMSTATE 1] change: 2, value: 9
[FORMSTATE 0] previous: [null, null, null, null, null, null], next: [null, null, 9, null, null, null]
My question is what causes this? How to change it to fulfill the expected case when a particular TextField
in list of TextField
at index i
changes, the riverpod state at index i
will also change?
2
Answers
Notice how you have two logs with state 0.
This probably means that you are rebuilding
FormState
every time you add a value.You should check where the
build()
method gets called and make sure you are not accidentaly rebuilding the state.There is no listener for your notifier and therefore it is auto disposed.
You can verify it by adding a log statement with
ref.dispose
inside the notifier or setup aProviderObserver
.https://docs-v2.riverpod.dev/docs/concepts/provider_observer
You could change the behaviour by adding
ref.watch(formStateProvider);
orref.listen(formStateProvider);
inside the widget’sbuild
method or set the notifier’skeepAlive
to true.