skip to Main Content

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


  1. 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.

    Login or Signup to reply.
  2. 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 a ProviderObserver.

    https://docs-v2.riverpod.dev/docs/concepts/provider_observer

    You could change the behaviour by adding ref.watch(formStateProvider); or ref.listen(formStateProvider); inside the widget’s build method or set the notifier’s keepAlive to true.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search