1

I am trying to use Riverpod state management. I have two TextFormField and I want to set the value of a Text by taking the sum of the values entered in each of the fields using a StateNotifierProvider.

In the following code, CashCounterData is a data model to be used by the StateNotifier, CashCounter. The notifier has two methods, setCount and setCash that are called in the onChanged method of each TextFormField.

final cashProvider = StateNotifierProvider<CashCounter, CashCounterData>((ref) => CashCounter());

class CashCounter extends StateNotifier<CashCounterData> {
  CashCounter() : super(_initialData);

  static const _initialData = CashCounterData(0, 0);

  void setCount(int value){
    state = CashCounterData(value, state.cash);
  }

  void setCash(value){
    state = CashCounterData(state.count, value);
  }

  int get count => state.count;
  int get cash => state.cash;
}

class CashCounterData {
  final int count;
  final int cash;

  const CashCounterData(this.count, this.cash);
}

Next, I implemented the UI and am trying to tie in the StateNotifierProvider defined above. However, when I enter values into each TextFormField, the Text widget is always displaying 0.

class CalculatableTextFormField extends HookWidget {
  @override
  Widget build(BuildContext context) {
    final cashCounterProvider = useProvider(cashProvider.notifier);
    final TextEditingController _count = TextEditingController();
    final TextEditingController _cash = TextEditingController();
    return Scaffold(
      body: Form(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(
                '${cashCounterProvider.count + cashCounterProvider.cash}'
            ),
            TextFormField(
              controller: _count,
              keyboardType: TextInputType.number,
              onChanged: (value)=>cashCounterProvider.setCount(int.parse(value)),
            ),
            TextFormField(
              controller: _cash,
              keyboardType: TextInputType.number,
              onChanged: (value)=>cashCounterProvider.setCash(int.parse(value)),
            )
          ],
        ),
      ),
    );
  }
}

What am I missing to get my desired behavior?

DolDurma
  • 15,753
  • 51
  • 198
  • 377

1 Answers1

1

You are watching the notifier, not the state. The state is what gets changed, and therefore notifies listeners.

It should work if you just change:

final cashCounterProvider = useProvider(cashProvider.notifier);

to:

final cashCounterProvider = useProvider(cashProvider);

Then, in your change handlers:

onChanged: (value) => context.read(cashProvider.notifier).setCash(int.tryParse(value) ?? 0),

When using a provider in a handler like this, prefer context.read as demonstrated above to avoid unnecessary rebuilds.

You also need to use hooks if you are putting your TextEditingControllers in the build method.

final TextEditingController _count = useTextEditingController();
final TextEditingController _cash = useTextEditingController();

All together, your solution is the following:

class CalculatableTextFormField extends HookWidget {
  @override
  Widget build(BuildContext context) {
    final cashCounterProvider = useProvider(cashProvider);
    final TextEditingController _count = useTextEditingController();
    final TextEditingController _cash = useTextEditingController();
    return Scaffold(
      body: Form(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text('${cashCounterProvider.count + cashCounterProvider.cash}'),
            TextFormField(
              controller: _count,
              keyboardType: TextInputType.number,
              onChanged: (value) =>
                  context.read(cashProvider.notifier).setCount(int.tryParse(value) ?? 0),
            ),
            TextFormField(
              controller: _cash,
              keyboardType: TextInputType.number,
              onChanged: (value) =>
                  context.read(cashProvider.notifier).setCash(int.tryParse(value) ?? 0),
            )
          ],
        ),
      ),
    );
  }
}
Alex Hartford
  • 5,110
  • 2
  • 19
  • 36
  • by changing codes, multiple typing and calculating doesn't work correctly, my meant is i can't type more numbers into both of inputs, you suppose i want to make a simple calculator, by each typing into inputs we should calculate values them – DolDurma Jul 29 '21 at 03:10
  • @DolDurma I updated my answer. Give it a try now. – Alex Hartford Jul 29 '21 at 15:50
  • could you please help me on this question? https://stackoverflow.com/q/68851765/1830228 – DolDurma Aug 19 '21 at 16:47