flutter riverpod从ChangeNotifier转换为使用StateNotifier

更新时间:2023-10-25 12:28

为了使用 StateNotifier,我们需要首先确保你的项目已经添加了 state_notifier 依赖。StateNotifierriverpod 的一部分,但它位于独立的包中。

对于这样的转换,我们可以从一个简单的 ChangeNotifier 示例开始。让我们假设有一个类 MyModel 满足下列条件:

class MyModel extends ChangeNotifier {
  int _counter = 0;

  int get counter => _counter;

  void increment() {
    _counter++;
    notifyListeners();
  }
}

要将它转换为使用 StateNotifier,我们需要进行几个步骤。

首先,我们需要将 _counter 私有属性换成 int 类型的状态。

class MyModel extends StateNotifier<int> {
  MyModel() : super(0);

  void increment() {
    state++;
  }
}

然后,我们需要在提供器中进行一些更改。如果你使用的是 ChangeNotifierProvider,那么你就需要将它换成 StateNotifierProvider

final myModelProvider = ChangeNotifierProvider((ref) => MyModel());

// becomes

final myModelProvider = StateNotifierProvider<MyModel, int>((ref) => MyModel());

最后,我们需要根据状态直接更改我们的使用方法。

final counter = useProvider(myModelProvider.select((value) => value.counter));

// becomes

final counter = useProvider(myModelProvider);

完成以上步骤后,我们就成功地将 ChangeNotifier 转换为使用 StateNotifier 了。

MyModel有多个值的处理counter name

如果 MyModel 类有多个值,例如叫做 _counter_name,你将需要创建一个新的类来持有这些状态。然后,你的 StateNotifier 类将维护这个新的状态对象。

让我们用下面的代码演示:

首先,我们创建一个新的 State 类来存储 _counter_name

class MyState {
  final int counter;
  final String name;

  MyState(this.counter, this.name);
}

然后,我们可以将 MyModel 修改为管理 MyState 而非独立的字段:

class MyModel extends StateNotifier<MyState> {
  MyModel() : super(MyState(0, ''));

  void increment() {
    state = MyState(state.counter + 1, state.name);
  }

  void setName(String name) {
    state = MyState(state.counter, name);
  }
}

在这里,每次我们的状态改变时,我们都在创建一个新的 MyState 实例。这样可以确保状态的不变性,这是 Redux 和其他状态管理库的主要原则。

最后,你的提供器和使用方法将需要相应地更新:

final myModelProvider = StateNotifierProvider<MyModel, MyState>((ref) => MyModel());

// Usage
final myState = useProvider(myModelProvider);
// Access counter and name via myState.counter and myState.name respectively

你还可以通过 myModelProvider.select 进行更细力度的选择。

final counter = useProvider(myModelProvider.select((value) => value.counter));
final name = useProvider(myModelProvider.select((value) => value.name));

这就是如何处理具有多个字段的 StateNotifier

模型继承自MyModel扩展变量的处理

假设你有一个继承自 MyModel 的模型,此模型扩展了更多的变量。对于这个问题有两种可能的方法。

方法一:扩展状态类

你可以扩展你的 MyState 类,并在子类中添加新的变量。

例如:

class ExtendedState extends MyState {
  final String extraVariable;

  ExtendedState(counter, name, this.extraVariable) : super(counter, name);
}

然后,你可以创建一个新的 StateNotifier 来使用你的 ExtendedState

class ExtendedModel extends StateNotifier<ExtendedState> {
  ExtendedModel() : super(ExtendedState(0, '', ''));

  void updateExtraVariable(String newValue) {
    state = ExtendedState(state.counter, state.name, newValue);
  }
}

方法二:组合 StateNotifier

另一种方法是你可以创建一个新的 StateNotifier,维护它自己的状态,并依赖你的初始 MyModel。这就像组合不同的 ChangeNotifier 类一样可以实现状态的共享。

例如:

class ExtraModel extends StateNotifier<String> {
  final MyModel myModel;

  ExtraModel(this.myModel) : super('') {
    myModel.addListener(update);
  }

  @override
  void dispose() {
    myModel.removeListener(update);
    super.dispose();
  }

  void update() {
    state = 'new state based on myModel: ${myModel.state}';
  }
}

这些都是根据你的具体需要选择的方法-你可能会发现,扩展你的状态类最简单,但如果你的状态类已经很复杂,或者你想要交叉引用不同的状态,那么组合 StateNotifier 类可能会是一个好方法。