38 lines
2.0 KiB
Dart
38 lines
2.0 KiB
Dart
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||
|
||
import 'auth_provider.dart';
|
||
|
||
/// 当前登录用户的身份。`null` = 未登录;非 null(可能是空串)= 已登录。
|
||
///
|
||
/// ## 它是干什么的
|
||
///
|
||
/// **所有「属于某个用户」的 provider 都应该 watch 它。** 换了人(含登出)
|
||
/// 它们就会自动重建,上一个人的余额、预算、聊天记录不会留给下一个。
|
||
///
|
||
/// 为什么不能只靠 `autoDispose`:`ProviderContainer` 在 main.dart 里创建一次、
|
||
/// 进程存活期内不重建,所以**不带 autoDispose 的 provider 会活到 App 结束**,
|
||
/// 登出根本不会清它们。新用户登录后读到的还是缓存值,连请求都不发 ——
|
||
/// 表现就是「换了账号还看到上一个人的余额」。
|
||
///
|
||
/// ## 两个刻意的选择
|
||
///
|
||
/// **不直接 watch(authProvider),而是 select 出用户名。**
|
||
/// 改头像、改昵称也会换掉 `AuthState`。而依赖 `sessionUserProvider` 的
|
||
/// 那一批 provider 一旦被标记失效就会重建 —— 换个头像就把聊天记录、
|
||
/// 笔记列表、记账草稿全清一遍,明显不对。select 到用户名后,这些变化
|
||
/// 根本不会传导出去。
|
||
///
|
||
/// (细究的话 Riverpod 对 `==` 相等的值不会通知下游,所以「watch 整个
|
||
/// AuthState 但返回值仍是用户名」其实也不会误清。但那是靠值相等兜底,
|
||
/// 语义上等于承认「改头像也算换人」,不该赌这个 —— 直接 select 更明确。)
|
||
///
|
||
/// **用 isLoggedIn 判空,而不是只看 `user?.username`。**
|
||
/// `AuthNotifier.load()` 在「本地有 token 但拿不到 userInfo」时会得到
|
||
/// `AuthState(token: t, user: null)`。只看 username 会把这种情况误判成
|
||
/// 未登录,于是各处的空态护栏把整个 App 打回空数据。
|
||
final sessionUserProvider = Provider<String?>((ref) {
|
||
return ref.watch(authProvider.select(
|
||
(auth) => auth.isLoggedIn ? (auth.user?.username ?? '') : null,
|
||
));
|
||
});
|