StateNotifierProvider 不使用 HookWidget 更新状态

StateNotifierProvider not updating state using HookWidget

我正在尝试使用 Riverpod 状态管理。我有两个 TextFormField,我想通过使用 StateNotifierProvider.

对每个字段中输入的值求和来设置 Text 的值

在下面的代码中,CashCounterDataStateNotifierCashCounter要使用的数据模型。通知程序有两个方法,setCountsetCash,它们在每个 TextFormField.

onChanged 方法中调用。
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);
}

接下来,我实现了 UI 并尝试加入上面定义的 StateNotifierProvider。但是,当我在每个 TextFormField 中输入值时,Text 小部件始终显示 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)),
            )
          ],
        ),
      ),
    );
  }
}

我缺少什么才能获得我想要的行为?

您正在查看通知程序,而不是状态。状态会发生变化,因此会通知听众。

如果你只是改变它应该工作:

final cashCounterProvider = useProvider(cashProvider.notifier);

至:

final cashCounterProvider = useProvider(cashProvider);

然后,在您的更改处理程序中:

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

在这样的处理程序中使用提供程序时,首选 context.read 如上所述,而不是 avoid unnecessary rebuilds

如果将 TextEditingControllers 放入构建方法中,则还需要使用挂钩。

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

总而言之,您的解决方案如下:

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),
            )
          ],
        ),
      ),
    );
  }
}