繁体   English   中英

如何在riverpod的statenotifier中访问值和函数

[英]How to access values and functions inside statenotifier in riverpod

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

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

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

这是我的状态通知器 class

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'))
                    ],
                  ));
            },
          ),
        ),
      ),
    );
  }
}

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

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

提前致谢:)

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

在小部件HomePage中,您实际上可以调用 function 内部提供程序,而无需使用context.read(provider)观察 state,因此您可以更改:

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

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

或者

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

另外如果你追求最好的性能,验证值的时候不需要监听(watch) signInStateNotifierProvider (因为您不会在小部件树中重建任何内容,只是获取数据)

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM