让我先说一下,我对 flutter 非常陌生,并且来自 Rails,其中 current_user 的设置要简单得多。 我正在创建一个功能性的 currentUserProvider:
@riverpod
User currentUser(CurrentUserRef ref, User user) {
User currentUser = user;
return currentUser;
}
}
这是建立在另一个提供商内的成功登录的基础上的,该提供商检查登录是否成功并保存其状态:
enum AuthenticationState {
initial,
loading,
success,
error,
}
@riverpod
class Authentication extends _$Authentication {
@override
AuthenticationState build() {
return AuthenticationState.initial;
}
Future<void> login() async {
//API Call made here and status returned:
if (response.statusCode == 200) {
User currentUser = User.fromJson((json.decode(response.body))['data']['attributes']);
currentUser = currentUser.copyWith(jwt: token);
ref.read(currentUserProvider(user: currentUser));
state = AuthenticationState.success;
} else {
await SecureStorage().deleteSecureData('jwt');
state = AuthenticationState.error;
}
}
}
我的问题是,在接下来的任何地方,我只想要 currentUserProvider 的缓存值,但它希望我将用户对象作为参数传递给它。 我不想将用户参数设置为可选,因为它永远不应该为空,并且用户会被重定向到登录屏幕。 有什么办法可以获取它的当前状态吗?我不想让参数可选,因为 User 对象不能为空...
AsyncNotifier
的状态是AsyncValue<User>
的一个实例,它具有例如方法:
isLoading
isRefreshing
isReloading
hasError
等除了
authenticationProvider
和 currentUserProvider
,您还可以:
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'user_notifier.g.dart';
class User {
const User(this.id);
const User.nobody() : id = -1;
final int id;
}
@riverpod
class UserNotifier extends _$UserNotifier {
@override
Future<User> build() async { // Alternatively Future<User?>
return const User.nobody(); // and return null.
}
Future<void> login() async { // Later probably with credentials
// Set the state to loading
state = const AsyncValue.loading();
// Set the state data
state = await AsyncValue.guard(() async {
return await Future.delayed(
const Duration(seconds: 5),
() => const User(1),
);
});
}
AuthenticationState get authenticationState {
if (state.isLoading) {
return AuthenticationState.loading;
}else if(state.hasError){
return AuthenticationState.error;
}
...
}
}
在下面的示例中,页面最初显示“无人登录”。单击登录后,将显示加载指示器,最后显示用户 ID。
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../providers/user_notifier.dart';
class UserPage extends ConsumerWidget {
const UserPage({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final userAsyncValue = ref.watch(userNotifierProvider);
return Scaffold(
appBar: AppBar(
title: const Text('User Page'),
),
body: Center(
child: switch (userAsyncValue) {
AsyncData(value: const User.nobody()) => const Text('Nobody logged in'),
AsyncData(value: final user) => Text(user.id.toString()),
AsyncError(:final error) => Text('Error: $error'),
_ => const Center(child: CircularProgressIndicator()),
},
),
floatingActionButton: FloatingActionButton(
onPressed: () async {
await ref.read(userNotifierProvider.notifier).login();
},
tooltip: 'Log in',
child: const Icon(Icons.login),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}