Flutter-如何将用户数据传递到所有视图 [英] Flutter - How to pass user data to all views

查看:70
本文介绍了Flutter-如何将用户数据传递到所有视图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是动荡世界和移动应用程序开发的新手,并且在如何在整个应用程序中传递用户数据方面遇到了麻烦。

I'm new to the flutter world and mobile app development and struggling with how I should pass user data throughout my app.

我已经尝试了几件事,但是似乎没有一个很好,我敢肯定我应该遵循最佳实践模式。

I've tried several things, but none seem great and I'm sure there are best practice patterns I should be following.

因为它使示例更容易,所以我使用firebase进行身份验证。
我目前有一条单独的登录路径。登录后,我希望大多数视图中的用户模型可以检查显示内容的权限,在抽屉中显示用户信息等...

Because it makes examples easier, I'm using firebase for authentication. I currently have a separate route for logging in. Once I'm logged in I want the User model in most views for checking permissions on what to show, displaying user info in the drawer, etc...

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

Firebase has an await firebaseAuth.currentUser(); Is it best practice to call this everywhere you might need the user? and if so, where is the best spot to place this call?

flutter代码实验室显示了一个很好的示例,允许用户在写入之前对用户进行身份验证。但是,如果页面需要检查auth以确定要构建的内容,则异步调用不能进入 build 方法。

The flutter codelab shows a great example authenticating users before allowing writes. However, if the page needs to check auth to determine what to build, the async call can't go in the build method.

我尝试过的一种方法是重写initState并启动调用以获取用户。将来完成时,我调用 setState 并更新用户。

One method I've tried is to override initState and kick off the call to get the user. When the future completes I call setState and update the user.

    FirebaseUser user;

    @override
    void initState() {
      super.initState();
      _getUserDetail();
    }

  Future<Null> _getUserDetail() async {
    User currentUser = await firebaseAuth.currentUser();
    setState(() => user = currentUser);
  }

这很不错,但是对于每个需要的小部件来说似乎都是很多仪式它。屏幕在没有用户加载的情况下也会闪烁,然后在将来完成时与用户更新。

This works decent, but seems like a lot of ceremony for each widget that needs it. There is also a flash when the screen loads without the user and then gets updated with the user upon the future's completion.

这也可以,但是要让用户通过所有可能需要访问它们的所有路线,视图及其状态,有很多样板。另外,在转换路线时,我们不能只执行 popAndPushNamed ,因为我们无法将变量传递给它。我们必须更改与此类似的路由:

This works too, but is a lot of boilerplate to pass the user through all routes, views, and their states that might need to access them. Also, we can't just do popAndPushNamed when transitioning routes because we can't pass variable to it. We have to change routes similar to this:

Navigator.push(context, new MaterialPageRoute(
    builder: (BuildContext context) => new MyPage(user),
));



继承的小部件



https://medium.com/@mehmetf_71205/inheriting-widgets-b7ac56dbbeb1

本文展示了一种使用 InheritedWidget 的不错的模式。当我将继承的小部件放置在MaterialApp级别时,当auth状态更改时,子代不会更新(我确定我做错了)

This article showed a nice pattern for using InheritedWidget. When I place the inherited widget at the MaterialApp level, the children aren't updating when the auth state changed (I'm sure I'm doing it wrong)

  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似乎也是一个不错的选择,但对于每条路线似乎都需要大量工作。在下面的部分示例中, _authenticateUser()在完成时获取用户并设置状态。

FutureBuilder

FutureBuilder also seems like a decent option, but seems to be a lot of work for each route. In the partial example below, _authenticateUser() is getting the user and setting state upon completion.

  @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();
        }
      },
    );
  }

我非常感谢有关最佳做法模式的建议或与使用资源的链接

I'd appreciate any advice on best practice patterns or links to resources to use for examples.

推荐答案

我建议您进一步研究继承的小部件。以下代码显示了如何在异步更新数据时使用它们:

I'd recommend investigating inherited widgets further; the code below shows how to use them with asynchronously updating data:

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-如何将用户数据传递到所有视图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆