Я реализовал аутентификацию пользователя с statenotifier
в riverpod, он работает, но я не знаю, как он работает таким образом. Мне нужно создать двух провайдеров: 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),
);
}
}
Вот как я получаю доступ к уведомителю о состоянии
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'))
],
));
},
),
),
),
);
}
}
Это нормально работает, но мне нужно знать, правильный ли это метод или я ошибаюсь. Есть ли другой способ добиться того же, что и я? Пожалуйста, дайте решение.
И то, что я делаю, правильно, пожалуйста, расскажите мне, как это работает таким образом. Мне нужно четкое понимание того, как это работает.
Заранее спасибо :)