ref.listen 方法不调用作为参数给出的方法

ref.listen method doesn't call one that is given as a parameter

我使用 Riverpod 进行状态管理

我想查看 StateNotifier<LoginNotifierData> 共享的字符串消息。我在 ConsumerState<LoginScreen> 中调用 ref.listen。但是虽然state.message在改,ref.listen里面的Function并没有被调用。我的问题是,为什么在更改 state 时不调用作为 ref.listen() 第二个参数给出的函数。

我使用 Equatable 库来比较对象

当我观察整个 LoginNotifierData 对象(没有 loginModelStateNotifierProvider.select())时,它也不起作用

通知程序中的登录方法(它更改了 state):

void login(String username, String password, WidgetRef ref) async {
    state.message = "Logowanie...";
    Either<Failure, LoginModel> setLogin = await ref
        .read(loginUseCaseProvider)
        .call(LoginParams(
        username: username,
        password: password));
    setLogin.fold((failure) {
      log('API Login: failure');
      state.message = failure.message;
      log(failure.toString());
    }, (loginModel) {
      log('API Login: success=${loginModel.success}');
      if (loginModel.success) {
        ref
            .read(loginModelStateNotifierProvider.notifier)
            .setLoginModel(loginModel);
        _storeUserData(loginModel, ref);
        ref.read(userRepositoryProvider).storeUsername(username);
        ref.read(userRepositoryProvider).storePassword(password);
        state.message = "";
      } else {
        state.message = loginModel.message;
        log('responseCode: ${loginModel.responseCode}');
      }
    });

  }

LoginNotifierData(state属于这种类型)

class LoginNotifierData extends Equatable {
  LoginModel loginModel = LoginModel("", 0, "", false, "", "", "", false, 0.0, "", "");
  String message = "";

  LoginNotifierData(this.loginModel, this.message);

  @override
  List<Object?> get props => [loginModel, message];
}

ref.listen 在 ConsumerState

@override Widget build 方法中调用
ref.listen<String>(
        loginModelStateNotifierProvider.select((value) => value.message),
            (_, message) {
          if(message.isNotEmpty) {
            widget.showLoaderDialog(context, message);
          } else {
            widget.hideDialog();
          }
        }
    );

loginModelStateNotifierProvider:

final loginModelStateNotifierProvider =
StateNotifierProvider<LoginModelStateNotifier, LoginNotifierData>(
        (ref) => LoginModelStateNotifier()
);

您无法通过 StateNotifier 中的 re-assigning 属性更新 state...您必须 re-assign state 本身。

使用 copyWith 方法可以做到这一点。

按照以下步骤操作:

1.在LoginNotifierData

中创建一个copyWith方法
class LoginNotifierData extends Equatable {
  LoginModel loginModel = LoginModel("", 0, "", false, "", "", "", false, 0.0, "", "");
  String message = "";

  LoginNotifierData(this.loginModel, this.message);

  LoginNotifierData copyWith({LoginModel? loginModel, String? message}){
     return LoginNotifierData(
        loginModel: loginModel,
        message: message,
     );
  }

  @override
  List<Object?> get props => [loginModel, message];
}

2。使用 copy with 方法 re-assign StateNotifier

中的状态
void login(String username, String password, WidgetRef ref) async {
    state = state.copyWith(message: "Logowanie...");
    Either<Failure, LoginModel> setLogin = await ref
        .read(loginUseCaseProvider)
        .call(LoginParams(
        username: username,
        password: password));
    setLogin.fold((failure) {
      log('API Login: failure');
      state = state.copyWith(message: failure.message);
      log(failure.toString());
    }, (loginModel) {
      log('API Login: success=${loginModel.success}');
      if (loginModel.success) {
        ref
            .read(loginModelStateNotifierProvider.notifier)
            .setLoginModel(loginModel);
        _storeUserData(loginModel, ref);
        ref.read(userRepositoryProvider).storeUsername(username);
        ref.read(userRepositoryProvider).storePassword(password);
        state = state.copyWith(message: "");
      } else {
        state = state.copyWith(message: loginModel.message);
        log('responseCode: ${loginModel.responseCode}');
      }
    });

  }