简体   繁体   中英

How to access values and functions inside statenotifier in riverpod

I implemented user authentication with the statenotifier in riverpod it works but I don't know how it works in such a manner. I have to create two providers, a StateNotifierProvider to read the values and a Provider for the same statenotifier to access the functions inside the statenotifier .

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

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

This is my statenotifier 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),
    );
  }
}

And this is how I access the 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'))
                    ],
                  ));
            },
          ),
        ),
      ),
    );
  }
}

This works fine but I need to know whether this is the right method or am I wrong. Is there any other method to achieve the same thing I am doing? Please give a solution.

And also what I am doing is right, Please tell me how it works in such a manner. I need a clear understanding of how it works.

Thanks in advance:)

I think signInProvider is redundant. It does nothing special but only listen to signInStateNotifierProvider .

Inside widget HomePage , you can actually call the function inside provider without watch the state by using context.read(provider) so you can chagne:

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

to

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

or

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

Also if you pursue the best performance, you don't need to listen to (watch) signInStateNotifierProvider when validating the value. (Because you don't rebuild anything in the widget tree, just fetching the data)

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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