Flutter-如何将用户数据传递到所有视图
问题内容:
我是瞬息万变的世界和移动应用程序开发的新手,正在为如何在整个应用程序中传递用户数据而苦苦挣扎。
我已经尝试了几件事,但是似乎都没有,我相信我应该遵循最佳实践模式。
因为它使示例更容易,所以我正在使用Firebase进行身份验证。我目前有一条单独的登录路径。登录后,我希望大多数视图中的用户模型可以检查显示内容的权限,在抽屉中显示用户信息等。
Firebase有一个await firebaseAuth.currentUser();
最佳实践,那就是在您可能需要用户的任何地方调用它?如果是这样,拨打此电话的最佳地点是哪里?
该扑代码实验室展示一个很好的例子,允许写入之前认证用户。但是,如果页面需要检查auth以确定要构建的内容,则异步调用不能进入该build
方法。
初始化状态
我尝试过的一种方法是重写initState并启动调用以获取用户。将来完成时,我会致电setState
并更新用户。
FirebaseUser user;
@override
void initState() {
super.initState();
_getUserDetail();
}
Future<Null> _getUserDetail() async {
User currentUser = await firebaseAuth.currentUser();
setState(() => user = currentUser);
}
这工作得体,但是对于需要它的每个小部件来说似乎都是很多仪式。屏幕在没有用户加载的情况下也会闪烁,然后在将来完成时随用户更新。
通过构造函数传递用户
这也可行,但是要让用户通过所有可能需要访问它们的所有路线,视图及其状态,这是很多样板。另外,我们不能仅popAndPushNamed
在转换路线时这样做,因为我们无法将变量传递给它。我们必须更改与此类似的路线:
Navigator.push(context, new MaterialPageRoute(
builder: (BuildContext context) => new MyPage(user),
));
继承的小部件
https://medium.com/@mehmetf_71205/inheriting-
widgets-b7ac56dbbebb1
本文展示了一个很好的使用模式InheritedWidget
。当我将继承的小部件放置在MaterialApp级别时,当身份验证状态更改时,子级不会更新(我确定我做错了)
FirebaseUser user;
Future<Null> didChangeDependency() async {
super.didChangeDependencies();
User currentUser = await firebaseAuth.currentUser();
setState(() => user = currentUser);
}
@override
Widget build(BuildContext context) {
return new UserContext(
user,
child: new MaterialApp(
title: 'TC Stream',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new LoginView(title: 'TC Stream Login', analytics: analytics),
routes: routes,
),
);
}
未来建设者
FutureBuilder似乎也是一个不错的选择,但对于每条路线似乎都需要大量工作。在下面的部分示例中,_authenticateUser()
获取用户并在完成时设置状态。
@override
Widget build(BuildContext context) {
return new FutureBuilder<FirebaseUser>(
future: _authenticateUser(),
builder: (BuildContext context, AsyncSnapshot<FirebaseUser> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return _buildProgressIndicator();
}
if (snapshot.connectionState == ConnectionState.done) {
return _buildPage();
}
},
);
}
我将对最佳实践模式的任何建议或用于示例的资源链接表示感谢。
问题答案:
我建议进一步调查继承的小部件。下面的代码显示了如何在异步更新数据时使用它们:
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
void main() {
runApp(new MaterialApp(
title: 'Inherited Widgets Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new Scaffold(
appBar: new AppBar(
title: new Text('Inherited Widget Example'),
),
body: new NamePage())));
}
// Inherited widget for managing a name
class NameInheritedWidget extends InheritedWidget {
const NameInheritedWidget({
Key key,
this.name,
Widget child}) : super(key: key, child: child);
final String name;
@override
bool updateShouldNotify(NameInheritedWidget old) {
print('In updateShouldNotify');
return name != old.name;
}
static NameInheritedWidget of(BuildContext context) {
// You could also just directly return the name here
// as there's only one field
return context.inheritFromWidgetOfExactType(NameInheritedWidget);
}
}
// Stateful widget for managing name data
class NamePage extends StatefulWidget {
@override
_NamePageState createState() => new _NamePageState();
}
// State for managing fetching name data over HTTP
class _NamePageState extends State<NamePage> {
String name = 'Placeholder';
// Fetch a name asynchonously over HTTP
_get() async {
var res = await http.get('https://jsonplaceholder.typicode.com/users');
var name = json.decode(res.body)[0]['name'];
setState(() => this.name = name);
}
@override
void initState() {
super.initState();
_get();
}
@override
Widget build(BuildContext context) {
return new NameInheritedWidget(
name: name,
child: const IntermediateWidget()
);
}
}
// Intermediate widget to show how inherited widgets
// can propagate changes down the widget tree
class IntermediateWidget extends StatelessWidget {
// Using a const constructor makes the widget cacheable
const IntermediateWidget();
@override
Widget build(BuildContext context) {
return new Center(
child: new Padding(
padding: new EdgeInsets.all(10.0),
child: const NameWidget()));
}
}
class NameWidget extends StatelessWidget {
const NameWidget();
@override
Widget build(BuildContext context) {
final inheritedWidget = NameInheritedWidget.of(context);
return new Text(
inheritedWidget.name,
style: Theme.of(context).textTheme.display1,
);
}
}