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.