我是瞬息万变的世界和移动应用程序开发的新手,正在为如何在整个应用程序中传递用户数据而苦苦挣扎。
我已经尝试了几件事,但是似乎都没有,我相信我应该遵循最佳实践模式。
因为它使示例更容易,所以我正在使用Firebase进行身份验证。我目前有一条单独的登录路径。登录后,我希望大多数视图中的用户模型可以检查显示内容的权限,在抽屉中显示用户信息等。
Firebase有一个await firebaseAuth.currentUser();最佳实践,那就是在您可能需要用户的任何地方调用它?如果是这样,拨打此电话的最佳地点是哪里?
await firebaseAuth.currentUser();
该扑代码实验室展示一个很好的例子,允许写入之前认证用户。但是,如果页面需要检查auth以确定要构建的内容,则异步调用不能进入该build方法。
build
我尝试过的一种方法是重写initState并启动调用以获取用户。将来完成时,我会致电setState并更新用户。
setState
FirebaseUser user; @override void initState() { super.initState(); _getUserDetail(); } Future<Null> _getUserDetail() async { User currentUser = await firebaseAuth.currentUser(); setState(() => user = currentUser); }
这工作得体,但是对于需要它的每个小部件来说似乎都是很多仪式。屏幕在没有用户加载的情况下也会闪烁,然后在将来完成时随用户更新。
这也可行,但是要让用户通过所有可能需要访问它们的所有路线,视图及其状态,这是很多样板。另外,我们不能仅popAndPushNamed在转换路线时这样做,因为我们无法将变量传递给它。我们必须更改与此类似的路线:
popAndPushNamed
Navigator.push(context, new MaterialPageRoute( builder: (BuildContext context) => new MyPage(user), ));
https://medium.com/@mehmetf_71205/inheriting- widgets-b7ac56dbbebb1
本文展示了一个很好的使用模式InheritedWidget。当我将继承的小部件放置在MaterialApp级别时,当身份验证状态更改时,子级不会更新(我确定我做错了)
InheritedWidget
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()获取用户并在完成时设置状态。
_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, ); } }