[英]How to access Riverpod StateNotifier state outside build without ConsumerWidget or HookWidget?
[英]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.