我刚接触Flutter 世界和移动应用程序开发,正在为如何在我的应用程序中传递用户数据而苦苦挣扎.

我try 了几种方法,但没有一种看起来很好,我确信我应该遵循一些最佳实践模式.

因为它使示例更简单,所以我使用Firebase进行身份验证. 我目前有单独的登录路由.一旦我登录,我希望在大多数视图中的用户模型来判断权限,显示什么,在抽屉中显示用户信息,等等…

FireBase的值是await firebaseAuth.currentUser();,在您可能需要用户的任何地方调用它是最佳实践吗?如果是这样的话,打这个电话的最佳地点是哪里?

flutter codelab显示了在允许写入之前对用户进行身份验证的一个很好的示例.但是,如果页面需要判断auth来确定要构建什么,则异步调用不能进入build方法.

初始状态

我try 过的一种方法是重写初始状态并启动调用以获取用户.future 完成后,我会拨打setState并更新用户.

    FirebaseUser user;

    @override
    void 初始状态() {
      super.初始状态();
      _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-b7ac56dbbeb1

本文展示了使用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

FutureBuilder似乎也是一个不错的 Select ,但每条路由似乎都有很多工作要做.在下面的部分示例中,_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,
    );
  }
}

Flutter相关问答推荐

Flutter 导致底部溢出

如何更改ElevatedButton的 colored颜色 以按下它?

当仅点击一行时,所有行都被选中

如何解决这个错误,同时获得的高度的小部件,因此高度的可用工作区域在Flutter ?

我如何才能收到每天重复的预定通知?

关闭模式,但再次打开时微件条件相同

查询满足AND条件的文档的FiRestore

在背景图像上排列定位徽标

使用Ffltter CREATE创建项目时,androidManifest.xml中缺少包属性

如何在点击查看措辞下方添加句子?

Dart/Flutter 泛型:类型 '(SearchFilterItemModel) => String' 不是类型 '(SearchFilterItemModel) => String' 的子类型

Flutter如何从深入嵌套的小部件中打开抽屉?

Flutter ImagePicker - 在 onPressed 中异步获取图像显示 lint 警告

Flutter - 如何将按钮对齐到行的右侧

对话框打开时如何使背景模糊?

Getx Flutter 在更新值时抛出空错误

如何判断 text.contains() 是否包含多个值

Flutter 中父容器顶部的 Gridview 间距额外区域

我想在数组中添加项目

Flutter Web Responsiveness 效率不高