StateNotifierProvider 不使用 HookWidget

问题描述

我正在尝试使用 Riverpod 状态管理。我有两个 TextFormField,我想通过使用 Text 取每个字段中输入的值的总和来设置 StateNotifierProvider 的值。

在以下代码中,CashCounterData 是由 StateNotifierCashCounter 使用的数据模型。通知程序有两个方法,setCountsetCash,它们在每个 onChangedTextFormField 方法中调用。

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

接下来,我实现了用户界面,并尝试结合上面定义的 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,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 放在 build 方法中,您还需要使用钩子。

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,onChanged: (value) =>
                  context.read(cashProvider.notifier).setCash(int.tryParse(value) ?? 0),)
          ],);
  }
}

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...