【问题标题】:How to access values and functions inside statenotifier in riverpod如何在riverpod的statenotifier中访问值和函数
【发布时间】:2021-02-02 19:05:50
【问题描述】:

我在riverpod 中使用statenotifier 实现了用户身份验证,但我不知道它是如何以这种方式工作的。我必须创建两个提供程序,一个StateNotifierProvider 来读取值,一个Provider 用于相同的statenotifier 来访问statenotifier 中的函数。

final signInStateNotifierProvider =
    StateNotifierProvider((ref) => SignInStateNotifier(authentication));

final signInProvider =
    Provider((ref) => ref.watch(signInStateNotifierProvider));

这是我的 statenotifier 类

class SignInStateNotifier extends StateNotifier<AuthFormStates> {
  SignInStateNotifier(this._authFacade) : super(AuthFormStates.initial());

  final SignInAuthFacade _authFacade;

  Future mapEventToState(SignInFormEvents event) async {
    event.map(
      // email changed
      emailChanged: (event) {
        state = state.copyWith(
          emailAddress: EmailAddress(event.email),
          authFailureOrSuccess: none(),
        );
      },
      // password changed
      passwordChanged: (event) {
        state = state.copyWith(
          password: Password(event.password),
          authFailureOrSuccess: none(),
        );
      },
      signInWithEmailAndPasswordPressed: (event) async {
        await _performActionWithEmailAndPassword(
          _authFacade.signInWithEmailAndPassword,
        );
      },
    );
  }

  Future _performActionWithEmailAndPassword(
    Future<Either<AuthFailure, Unit>> Function({
      @required EmailAddress emailAddress,
      @required Password password,
    })
        action,
  ) async {
    Either<AuthFailure, Unit> result;
    final isEmailValid = state.emailAddress.isValid();
    final isPasswordValid = state.password.isValid();

    if (isEmailValid && isPasswordValid) {
      state = state.copyWith(
        isSubmitting: true,
        authFailureOrSuccess: none(),
      );

      result = await action(
        emailAddress: state.emailAddress,
        password: state.password,
      );

      state = state.copyWith(
        authFailureOrSuccess: some(result),
      );
    }
    state = state.copyWith(
      isSubmitting: false,
      showErrorMessage: true,
      authFailureOrSuccess: optionOf(result),
    );
  }
}

这就是我访问 statenotifier 的方式

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Scaffold(
        body: ProviderListener<AuthFormStates>(
          provider: signInStateNotifierProvider.state,
          onChange: (context, state) {
            state.authFailureOrSuccess.fold(
              () {},
              (either) => either.fold(
                (failure) {
                  return null;
                },
                (success) => null,
              ),
            );
          },
          child: Consumer(
            builder: (context, watch, child) {
              final providerState = watch(signInProvider);
              final stateNotifierState =
                  watch(signInStateNotifierProvider.state);
              return Form(
                  autovalidateMode: AutovalidateMode.onUserInteraction,
                  child: Column(
                    children: [
                      TextFormField(
                        onChanged: (value) => providerState.mapEventToState(
                            SignInFormEvents.emailChanged(value)),
                        validator: (_) => stateNotifierState
                            .emailAddress.validatedObject
                            .fold(
                                (l) => l.maybeMap(
                                    orElse: () => null,
                                    invalidEmail: (_) => 'Invalid Email'),
                                (_) => null),
                      ),
                      TextFormField(
                        onChanged: (value) => providerState.mapEventToState(
                            SignInFormEvents.passwordChanged(value)),
                        validator: (_) =>
                            stateNotifierState.password.validatedObject.fold(
                                (l) => l.maybeMap(
                                    orElse: () => null,
                                    invalidPassword: (_) => 'Invalid Password'),
                                (_) => null),
                      ),
                      TextButton(
                          onPressed: () {
                            providerState.mapEventToState(const SignInFormEvents
                                .signInWithEmailAndPasswordPressed());
                          },
                          child: const Text('Hello World'))
                    ],
                  ));
            },
          ),
        ),
      ),
    );
  }
}

这很好,但我需要知道这是正确的方法还是我错了。有没有其他方法可以实现我正在做的同样的事情?请给出解决方案。

而且我所做的也是正确的,请告诉我它是如何以这种方式工作的。我需要清楚地了解它的工作原理。

提前致谢:)

【问题讨论】:

    标签: flutter dart flutter-layout flutter-dependencies riverpod


    【解决方案1】:

    我认为signInProvider 是多余的。它没有什么特别的,只是听signInStateNotifierProvider。

    在 HomePage 小部件内部,您可以通过 context.read(provider) 实际调用提供程序内部的函数而无需查看状态,因此您可以更改:

    final providerState = watch(signInProvider);
    providerState.mapEventToState(...)
    

    到

    final providerState = context.read(signInStateNotifierProvider);
    providerState.mapEventToState(...)
    

    或

    context.read(signInStateNotifierProvider).mapEventToState(...)
    

    另外如果你追求最好的性能,验证值的时候不需要听(看)signInStateNotifierProvider。 (因为你没有在小部件树中重建任何东西,只是获取数据)

    validator: (_) => context.read(signInStateNotifierProvider).emailAddress.validatedObject...
    

    【讨论】:

    • 谢谢。我已经纠正了我的错误。但是你能解释一下它是如何工作的吗?为什么我不能仅仅通过这个来访问statenotifier 中的函数。 final signInStateNotifierProvider =StateNotifierProvider((ref) =&gt; SignInStateNotifier(authentication));
    • 嗨~你的意思是在你评论的行里面吗?这一行就像提供者的初始构造函数。它只涉及自身的构造。 ref 可用于监听其他提供者并重建自身。 Riverpod Doc, context.read
    • 我的问题是为什么我不能只使用final stateNotifierState = watch(signInStateNotifierProvider.state); 来完成它,为什么我应该单独阅读statenotifier 以便访问其中的函数。
    • 简而言之(我认为),我认为这是因为 Availability 和 Performance。 1.对于用法,watch(provider)只能在构建时使用(在Build方法中),而您可以在任何地方使用read(例如onPress,onTap)。 2.只使用read时,可以避免不必要的rebuild。否则每次状态变化时都会重建小部件。
    猜你喜欢
    • 2021-04-21
    • 2021-04-04
    • 2021-05-24
    • 2021-02-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-27
    • 1970-01-01
    相关资源
    最近更新 更多