如何使用 Riverpods StateNotifierProvider 处理复杂状态

How to handle complex state with Riverpods StateNotifierProvider

我有一个非常大、复杂的应用程序,其中包含许多页面,其中包含带有大量字段(文本、日期选择、组合框等)的输入表单,因此状态相当大。 我正在从 Provider 切换到 Riverpod,建议的状态管理方式似乎主要是 StateNotifierProvider。但是那个状态是不可变的,这意味着你必须在每次更改时克隆完整的状态。 我需要的是 Providers ChangeNotifierProvider(Riverpod 也有),以便能够拥有可变状态并更好地控制何时触发侦听器上的重建。 但是 Riverpod 不鼓励使用 ChangeNotifierProvider,这让我有点紧张。可能是我没有真正理解StateNotifierProvider这个概念。

那么问题来了,如何使用StateNotifierProvider来处理复杂的状态呢?真的有必要总是克隆状态吗?

编辑:复杂的是指更多的字段(例如 50 个)以及列表和对象结构。您可以克隆它,但它很昂贵,而且感觉 natural/smart 对每个小改动都这样做。这真的是预期的方式吗?有没有办法在仍然使用 StateNotifierProvider 的同时进行克隆?

首先,我不建议使用 ChangeNotifier(可变状态)而不是 StateNotifier(不可变状态),因为 flutter 中状态管理的最佳实用方法是使用不可变状态。

你可以使用freezedfreezed_annotation来帮助你复制状态,每次你想发出新的状态,你只需复制旧的状态并改变你需要的。 像这样

state = state.copyWith(var1: "new var");

这里是一个使用冻结的复杂状态的例子

  1. freezed_annotation 添加到您的 dependencies
  2. freezed and build_runner 添加到您的 dev_dependencies
  3. 创建你的状态complex_state.dart像这样,改变工厂构造函数来满足你的需要
import 'package:freezed_annotation/freezed_annotation.dart';

part 'complex_state.freezed.dart';

@freezed
class ComplexState with _$ComplexState {
  const ComplexState._();

  const factory ComplexState({
    required String var1,
    required double var2,
    required bool var3,
    required int var4,
  }) = _ComplexState;
}
  1. 运行终端中的这个命令
flutter pub run build_runner build --delete-conflicting-outputs
  1. freezed 将生成您的 ComplexState 以及一些其他有用的方法,例如 copyWith() 现在您可以在 StateNotifier
  2. 中使用它们

这里有一个使用 StateNotifier 和 Riverpod 的例子

final complexStateNotifierProvider = StateNotifierProvider(
  (ref) {
    const initialState = ComplexState(
      var1: "var1",
      var2: 90.0,
      var3: true,
      var4: 90,
    );
    return ComplexStateNotifier(initialState);
  },
);

abstract class ComplexStateEvent {}

class ComplexStateEventDoSomething implements ComplexStateEvent {}

class ComplexStateNotifier extends StateNotifier<ComplexState> {
  ComplexStateNotifier(ComplexState state) : super(state);

  void onEvent(ComplexStateEvent event) {
    if (event is ComplexStateEventDoSomething) {
      state = state.copyWith(var1: "new value");
    }
  }
}

注意:freezed 还支持可空和默认构造函数参数,您可以将其用于初始状态,请在其 pub.dev 页面

上阅读更多内容