首页 > 解决方案 > 实施 ChangeNotifier 与 StateNotifier

问题描述

我对Provider包非常熟悉,并将其与ChangeNotifier.

假设我有 3 个具有不同功能的 getter 和方法:

  1. 切换加载
  2. 切换图像加载
  3. 切换 ObsecurePassword

使用 ChangeNotifer

import 'package:flutter/foundation.dart';

class GlobalChangeNotifier extends ChangeNotifier {
  bool _isLoading = false;
  bool _isImageLoading = false;
  bool _isObsecurePassword = false;

  bool get isLoading => _isLoading;
  bool get isImageLoading => _isImageLoading;
  bool get isObsecurePassword => _isObsecurePassword;

  void setLoading(bool value) {
    _isLoading = value;
    notifyListeners();
  }

  void setImageLoading(bool value) {
    _isImageLoading = value;
    notifyListeners();
  }

  void setObsecurePassword(bool value) {
    _isObsecurePassword = !value;
    notifyListeners();
  }
}

final globalChangeNotifier = GlobalChangeNotifier();

如果我正在使用ChangeNotifier,我只需要创建 1 个文件并调用类似的方法globalChangeNotifier.METHOD()或类似的值globalChangeNotifier.value

但是现在,我已经了解了Riverpod包,并且在文档中,它使用StateNotifier.

我想将我以前的代码ChangeNotifierStateNotifier. 但据我了解,StateNotifier 只能保存 1 种类型的数据,所以如果我想迁移上面的代码,我应该创建 3 个文件,比方说:

  1. provider_isloading.dart,
  2. provider_isimageloading.dart
  3. provider_obsecurepassword.dart.

使用 StateNotifier

// provider_isloading.dart
class IsImageLoading extends StateNotifier<bool> {
  IsImageLoading() : super(false);

  void toggleImageLoading(bool value) {
    state = value;
  }
}

final isImageLoadingProvider = StateNotifierProvider((ref) => IsImageLoading());

// provider_isimageloading.dart

class IsLoading extends StateNotifier<bool> {
  IsLoading() : super(false);
  void toggleLoading(bool value) => state = value;
}

final isLoadingProvider = StateNotifierProvider((ref) => IsLoading());

// provider_obsecurepassword.dart
class IsObsecurePassword extends StateNotifier<bool> {
  IsObsecurePassword() : super(false);

  void toggleObsecurePassword(bool value) {
    state = !value;
  }
}

final isObsecurePasswordProvider = StateNotifierProvider((ref) => IsObsecurePassword());

而且我还需要创建 1 个文件来导出所有这些文件:

GlobalStateNotifer.dart

export './provider_loading.dart';
export './provider_imageloading.dart';
export './provider_obsecurepassword.dart';

我的问题是,按照我之前的解释,这是最好的做法吗?

我的文件夹结构

我的文件夹结构

标签: flutterriverpod

解决方案


使用 Riverpod 时,在它们提供的类上创建静态提供程序非常有意义。从您的示例中,您可以重构为:

class IsImageLoading extends StateNotifier<bool> {
  IsImageLoading() : super(false);

  static final provider = StateNotifierProvider((ref) => IsImageLoading());

  void toggleImageLoading(bool value) {
    state = value;
  }
}

您还应该考虑是否需要您的提供者在您实际使用它们的课程之外可用。有些事情告诉我,除了登录页面之外,您可能不会在任何地方使用您的密码提供程序。考虑在该类中创建一个私有提供程序。

但是,如果您希望保持当前的方法,您可以创建一个A包含 3 个 bool 值的类和一个扩展的类StateNotifier<A>

例如:

enum LoadingType { A, B, C }

class LoadingToggles {
  bool A, B, C;

  LoadingToggles({this.A = false, this.B = false, this.C = false});

  static final provider = StateNotifierProvider.autoDispose((ref) => LoadingState(LoadingToggles()));
}

class LoadingState extends StateNotifier<LoadingToggles> {
  LoadingState(LoadingToggles state) : super(state ?? LoadingToggles());

  void toggle(LoadingType type) {
    switch (type) {
      case LoadingType.A:
        state.A = !state.A;
        break;
      case LoadingType.B:
        state.B = !state.B;
        break;
      case LoadingType.C:
        state.C = !state.C;
        break;
      default:
        // Handle error state
    }
  }
}

最后,只想补充一点,可能有更好的方法来处理整体加载。考虑是否可以将 FutureProvider/StreamProvider 与 Riverpod 的 AsyncValue 一起使用,而不是手动切换加载状态。


推荐阅读