如何在 riverpod 中访问 statenotifier 内的值和函数
How to access values and functions inside statenotifier in riverpod
我在 riverpod 中使用 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
.
在 widget HomePage 内部,您实际上可以调用 provider 内部的函数,而无需使用 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...
我在 riverpod 中使用 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
.
在 widget HomePage 内部,您实际上可以调用 provider 内部的函数,而无需使用 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...