【发布时间】:2021-05-14 18:19:54
【问题描述】:
我正在使用 flutter_bloc 并创建了一个 sessionState,当用户成功通过身份验证并且状态保存用户对象 (did) 时触发该会话状态。
我使用 Cubit 来更改状态,然后在 ui 中显示不同的屏幕。但是,每当我想访问保存用户信息的已验证 sessionState 的 did 对象时,我必须在每个文件中创建一个 if else 语句来检查 sessionState 是否为 Verified,如果这是真的,我可以访问与state.did 反对。
我很想知道是否可以将此 did 对象提供给所有底层小部件,而无需手动传递每个小部件。
我希望能够从上下文中访问 did 对象,以便我可以在提供它的任何地方访问它。
我的会话状态:
abstract class SessionState {}
class UnkownSessionState extends SessionState {}
class Unverified extends SessionState {}
class Verified extends SessionState {
Verified({required this.did});
final Did did;
}
SessionCubit 启动状态用于定义应用的全局状态并因此显示不同的屏幕。
class SessionCubit extends Cubit<SessionState> {
SessionCubit(this.commonBackendRepo) : super(UnkownSessionState()) {
attemptGettingDid();
}
final CommonBackendRepo commonBackendRepo;
final SecureStorage secureStorage = SecureStorage();
Future<void> attemptGettingDid() async {
try {
//more logic
emit(Unverified());
} catch (e) {
emit(Unverified());
}
}
void showUnverified() => emit(Unverified());
void showSession(Did did) {
emit(Verified(did: did));
}
}
这是我目前在每个文件中访问 did 对象的方式:
BlocBuilder<SessionCubit, SessionState>(builder: (context, state) {
if (state is Verified) {
return CustomScrollView(
slivers: <Widget>[
SliverAppBar(
elevation: 0.0,
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
title: Text(
state.did.username,
style: Theme.of(context).textTheme.headline5,
),
),
SliverToBoxAdapter(
child: Padding(
padding: const EdgeInsets.all(20.0),
child: CredentialDetailsView(),
))
],
);
} else {
return const Text("Unverified");
}
});
编辑:
这就是我想象我的场景的最佳解决方案的方式:
- 创建 if/else 以检查状态是否在一个父窗口小部件中得到验证。
- 如果状态已验证,则使用“did”对象创建一个作为子级的 Provider,这样该 Provider 的子级就不必访问 SessionState,而只需访问提供的
did对象。
回应罗伯特·桑德伯格的回答
我还有一个AppNavigator,可以启动authNavigator 或sessionNavigator。所以sessionNavigator 是所有小部件的父小部件,仅当状态为Verified 时才会显示。所以我认为这将是一个用Provider.value 包装 sessionNavigator 的好地方,正如你所解释的那样。
我用 Provider.value 小部件包装了我的 SessionNavigator 并提供了状态对象:
class AppNavigator extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocBuilder<SessionCubit, SessionState>(
builder: (context, state) {
return Navigator(
pages: [
if (state is UnkownSessionState)
MaterialPage(child: StartupScreen()),
//show auth flow
if (state is Unverified)
MaterialPage(
child: BlocProvider(
create: (context) => AuthCubit(context.read<SessionCubit()),
child: AuthNavigator(),
)),
//show session flow
if (state is Verified)
MaterialPage(
child: Provider.value(
// here I can access the state.did object
value: state,
child: SessionNavigator(),
))
],
onPopPage: (route, result) => route.didPop(result),
);
},
);
}
}
为了测试,我尝试在我的主屏幕中观看提供的值,它是 SessionNavigator 的子屏幕:
...
class _HomeState extends State<Home> {
@override
Widget build(BuildContext context) {
//
final sessionState = context.watch<SessionState>();
return CustomScrollView(
slivers: <Widget>[
SliverAppBar(
floating: true,
expandedHeight: 60.0,
backgroundColor: Colors.white,
flexibleSpace: FlexibleSpaceBar(
title: Text(
// I can't access state.did because value is of type SessionState
sessionState.did,
style: Theme.of(context).textTheme.headline6,
),
titlePadding:
const EdgeInsetsDirectional.only(start: 20, bottom: 16)),
)
],
);
}
}
但是因为我的值的类型是SessionState,所以我无法访问底层 Verified 状态的 did 对象。我想提供 state.did 对象,但我不知道如何查看该类型。
我还收到了我的主屏幕在构建上下文中找不到提供程序的错误。会不会因为我的主屏幕有 Navigator 作为父级而发生?
这是我的应用架构的可视化:
【问题讨论】:
-
如果您希望我将我的答案翻译到您的特定课程,请告诉我。我为即将到来的观众写了一些笼统的东西。