将两个 Streams 合并为一个 StreamProvider
Combine two Streams into one StreamProvider
我有两个流:
Stream<FirebaseUser> FirebaseAuth.instance.onAuthStateChanged
Stream<User> userService.streamUser(String uid)
我的 userService 需要经过身份验证的 FirebaseUser 的 uid 作为参数。
因为我可能需要在我的应用程序的多个部分访问 streamUser() 流,所以我希望它成为我项目根目录下的提供者。
这是我的 main.dart 的样子:
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
var auth = FirebaseAuth.instance;
var userService = new UserService();
return MultiProvider(
providers: [
Provider<UserService>.value(
value: userService,
),
],
child: MaterialApp(
home: StreamBuilder<FirebaseUser>(
stream: auth.onAuthStateChanged,
builder: (context, snapshot) {
if (!snapshot.hasData) return LoginPage();
return StreamProvider<User>.value(
value: userService.streamUser(snapshot.data.uid),
child: HomePage(),
);
}),
),
);
}
}
问题是,当我导航到另一个页面时,MaterialApp 下面的所有内容都被更改了,我失去了 StreamProvider 的上下文。
有没有办法将 StreamProvider 添加到 MultiProvider 提供者列表中?
因为当我尝试时,我还必须为 FirebaseUser 创建另一个 onAuthStateChanged 流,我不知道如何将它们组合成一个 Provider。
所以这似乎工作正常:
StreamProvider<User>.value(
value: auth.onAuthStateChanged.transform(
FlatMapStreamTransformer<FirebaseUser, User>(
(firebaseUser) => userService.streamUser(firebaseUser.uid),
),
),
),
如果有人对此在某些极端情况下有疑问,请告诉我。
也许你可以试试这个方法:
main.dart
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
Provider<FirebaseUser>(
builder: (_) => FirebaseUser(),
),
],
child: AuthWidgetBuilder(builder: (context, userSnapshot) {
return MaterialApp(
theme: ThemeData(primarySwatch: Colors.indigo),
home: AuthWidget(userSnapshot: userSnapshot),
);
}),
);
}
}
AuthWidgetBuilder.dart
Used to create user-dependant objects that need to be accessible by
all widgets. This widget should live above the [MaterialApp]. See
[AuthWidget], a descendant widget that consumes the snapshot generated
by this builder.
class AuthWidgetBuilder extends StatelessWidget {
const AuthWidgetBuilder({Key key, @required this.builder}) : super(key: key);
final Widget Function(BuildContext, AsyncSnapshot<User>) builder;
@override
Widget build(BuildContext context) {
final authService =
Provider.of<FirebaseUser>(context, listen: false);
return StreamBuilder<User>(
stream: authService.onAuthStateChanged,
builder: (context, snapshot) {
final User user = snapshot.data;
if (user != null) {
return MultiProvider(
providers: [
Provider<User>.value(value: user),
Provider<UserService>(
builder: (_) => UserService(uid: user.uid),
),
],
child: builder(context, snapshot),
);
}
return builder(context, snapshot);
},
);
}
}
AuthWidget.dart
Builds the signed-in or non signed-in UI, depending on the user
snapshot. This widget should be below the [MaterialApp]. An
[AuthWidgetBuilder] ancestor is required for this widget to work.
class AuthWidget extends StatelessWidget {
const AuthWidget({Key key, @required this.userSnapshot}) : super(key: key);
final AsyncSnapshot<User> userSnapshot;
@override
Widget build(BuildContext context) {
if (userSnapshot.connectionState == ConnectionState.active) {
return userSnapshot.hasData ? HomePage() : SignInPage();
}
return Scaffold(
body: Center(
child: CircularProgressIndicator(),
),
);
}
}
本文来自 Andrea Bizotto 的 advance provider 教程。
但是我根据你上面的代码定制了一些代码。
希望这有效,祝你好运!
Reference:
https://www.youtube.com/watch?v=B0QX2woHxaU&list=PLNnAcB93JKV-IarNvMKJv85nmr5nyZis8&index=5
我有两个流:
Stream<FirebaseUser> FirebaseAuth.instance.onAuthStateChanged
Stream<User> userService.streamUser(String uid)
我的 userService 需要经过身份验证的 FirebaseUser 的 uid 作为参数。
因为我可能需要在我的应用程序的多个部分访问 streamUser() 流,所以我希望它成为我项目根目录下的提供者。
这是我的 main.dart 的样子:
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
var auth = FirebaseAuth.instance;
var userService = new UserService();
return MultiProvider(
providers: [
Provider<UserService>.value(
value: userService,
),
],
child: MaterialApp(
home: StreamBuilder<FirebaseUser>(
stream: auth.onAuthStateChanged,
builder: (context, snapshot) {
if (!snapshot.hasData) return LoginPage();
return StreamProvider<User>.value(
value: userService.streamUser(snapshot.data.uid),
child: HomePage(),
);
}),
),
);
}
}
问题是,当我导航到另一个页面时,MaterialApp 下面的所有内容都被更改了,我失去了 StreamProvider 的上下文。
有没有办法将 StreamProvider 添加到 MultiProvider 提供者列表中? 因为当我尝试时,我还必须为 FirebaseUser 创建另一个 onAuthStateChanged 流,我不知道如何将它们组合成一个 Provider。
所以这似乎工作正常:
StreamProvider<User>.value(
value: auth.onAuthStateChanged.transform(
FlatMapStreamTransformer<FirebaseUser, User>(
(firebaseUser) => userService.streamUser(firebaseUser.uid),
),
),
),
如果有人对此在某些极端情况下有疑问,请告诉我。
也许你可以试试这个方法:
main.dart
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
Provider<FirebaseUser>(
builder: (_) => FirebaseUser(),
),
],
child: AuthWidgetBuilder(builder: (context, userSnapshot) {
return MaterialApp(
theme: ThemeData(primarySwatch: Colors.indigo),
home: AuthWidget(userSnapshot: userSnapshot),
);
}),
);
}
}
AuthWidgetBuilder.dart
Used to create user-dependant objects that need to be accessible by all widgets. This widget should live above the [MaterialApp]. See [AuthWidget], a descendant widget that consumes the snapshot generated by this builder.
class AuthWidgetBuilder extends StatelessWidget {
const AuthWidgetBuilder({Key key, @required this.builder}) : super(key: key);
final Widget Function(BuildContext, AsyncSnapshot<User>) builder;
@override
Widget build(BuildContext context) {
final authService =
Provider.of<FirebaseUser>(context, listen: false);
return StreamBuilder<User>(
stream: authService.onAuthStateChanged,
builder: (context, snapshot) {
final User user = snapshot.data;
if (user != null) {
return MultiProvider(
providers: [
Provider<User>.value(value: user),
Provider<UserService>(
builder: (_) => UserService(uid: user.uid),
),
],
child: builder(context, snapshot),
);
}
return builder(context, snapshot);
},
);
}
}
AuthWidget.dart
Builds the signed-in or non signed-in UI, depending on the user snapshot. This widget should be below the [MaterialApp]. An [AuthWidgetBuilder] ancestor is required for this widget to work.
class AuthWidget extends StatelessWidget {
const AuthWidget({Key key, @required this.userSnapshot}) : super(key: key);
final AsyncSnapshot<User> userSnapshot;
@override
Widget build(BuildContext context) {
if (userSnapshot.connectionState == ConnectionState.active) {
return userSnapshot.hasData ? HomePage() : SignInPage();
}
return Scaffold(
body: Center(
child: CircularProgressIndicator(),
),
);
}
}
本文来自 Andrea Bizotto 的 advance provider 教程。 但是我根据你上面的代码定制了一些代码。 希望这有效,祝你好运!
Reference: https://www.youtube.com/watch?v=B0QX2woHxaU&list=PLNnAcB93JKV-IarNvMKJv85nmr5nyZis8&index=5