实现ChangeNotifier与StateNotifier

时间:2020-07-17 03:54:22

标签: flutter

我对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

我想将以前的代码从ChangeNotifier迁移到StateNotifier。 但据我了解,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';

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

我的文件夹的结构

My Folder's Structure

3 个答案:

答案 0 :(得分:1)

使用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一起使用,而不是手动切换加载状态。

答案 1 :(得分:0)

我认为你应该像下面的代码一样使用不可变的类

@immutable
abstract class GlobalState {
  const GlobalState();
}

class IsImageLoading extends GlobalState {
  const IsImageLoading();
}

class IsLoading extends GlobalState {
  const IsLoading();
}

class IsObsecurePassword extends GlobalState {
  const IsObsecurePassword();
}

您的 StateNotifier 将如下所示

class GlobalStateNotifier extends StateNotifier<GlobalState> {
  GlobalStateNotifier(GlobalState state) : super(state);

  void changeState(GlobalState newState) {
    state = newState;
  }
}

答案 2 :(得分:0)

很晚的回复,但我现在正在搜索相同的内容,但我没有找到使用 riverpod 或 StateNotifier 的正确方法,但您可能应该像使用 ChangeNotifier 一样使用,或者对于他们应该像 flutter_bloc 逻辑一样使用 flutter_bloc 用户......或两者兼而有之。

对于这种情况以及我所阅读的内容,我将只使用一个 dart 文件来放置所有代码,例如您的 changenotifier 类,并为 IsImageLoading, isLoading, isObscurePassword 制作简单的 stateproviders

在另一个 MyViewProvider 类中,您可以更改那些 statesProvider 的状态,或者不创建它并直接在视图中更改状态。


final isImageLoadingProvider = StateProvider((ref) => false);

final isLoadingProvider = StateProvider((ref) => false);

final isObscurePasswordProvider = StateProvider((ref) => false);

final myViewProvider = Provider<MyViewProvider>((ref) {
  return MyViewProvider(ref.read);
});

class MyViewProvider {
  MyViewProvider(this._read);

  final Reader _read;

  void setLoading(bool value) {
    _read(isLoadingProvider).state = value;
  }

  void setImageLoading(bool value) {
    _read(isImageLoadingProvider).state = value;
  }

  void setObscurePassword() {
    final isObscure = _read(isLoadingProvider).state;
    _read(isObscurePasswordProvider).state = !isObscure;
  }
}

如有任何意见或改进,我将不胜感激