webentwicklung-frage-antwort-db.com.de

Flattern - Wie werden Benutzerdaten an alle Ansichten übergeben?

Ich bin neu in der Welt des Flatterns und der Entwicklung mobiler Apps und habe Probleme damit, wie ich Benutzerdaten in meiner App weitergeben sollte.

Ich habe mehrere Dinge ausprobiert, aber keines scheint großartig zu sein, und ich bin mir sicher, dass es die besten Übungsmuster gibt, denen ich folgen sollte.

Da es die Beispiele einfacher macht, verwende ich firebase für die Authentifizierung. Ich habe derzeit eine separate Route zum Anmelden. Sobald ich angemeldet bin, möchte ich, dass das Benutzermodell in den meisten Ansichten angezeigt wird, um die Berechtigungen für das Anzeigen und Anzeigen zu überprüfen Benutzerinfo in der Schublade etc ...

Firebase hat eine await firebaseAuth.currentUser();. Ist es am besten, diese Funktion überall anzurufen, wo Sie den Benutzer benötigen? Und wenn ja, wo ist der beste Ort für diesen Anruf? 

Das Flatter-Codelab zeigt ein hervorragendes Beispiel für die Authentifizierung von Benutzern, bevor Schreibvorgänge zugelassen werden. Wenn die Seite jedoch auth überprüfen muss, um festzustellen, was erstellt werden soll, kann der async-Aufruf nicht in der build-Methode ausgeführt werden.

initState

Eine Methode, die ich versucht habe, ist, initState zu überschreiben und den Anruf abzustoßen, um den Benutzer zu erreichen. Wenn die Zukunft abgeschlossen ist, rufe ich setState an und aktualisiere den Benutzer. 

    FirebaseUser user;

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

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

Dies funktioniert anständig, scheint aber für jedes Widget, das es benötigt, viel Zeremonie. Es gibt auch einen Blitz, wenn der Bildschirm ohne Benutzer geladen wird und nach Abschluss der zukünftigen Installation mit dem Benutzer aktualisiert wird.

Übergeben Sie den Benutzer durch den Konstruktor

Dies funktioniert auch, aber es ist eine Menge Boilerplate, um den Benutzer durch alle Routen, Ansichten und deren Status zu führen, die möglicherweise auf sie zugreifen müssen. Wir können auch nicht einfach popAndPushNamed beim Überführen von Routen verwenden, da wir keine Variablen an sie übergeben können. Wir müssen ähnliche Routen ändern:

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

Geerbte Widgets

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

Dieser Artikel zeigte ein Nice-Muster für die Verwendung von InheritedWidget. Wenn ich das geerbte Widget auf der MaterialApp-Ebene platziere, werden die Kinder nicht aktualisiert, wenn sich der Auth-Status geändert hat (ich bin sicher, ich mache es falsch).

  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 scheint auch eine anständige Option zu sein, scheint aber für jede Route eine Menge Arbeit zu sein. Im folgenden Teilbeispiel erhält _authenticateUser() den Benutzer und den Status nach Abschluss. 

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

Ich würde mich über Ratschläge zu Best-Practice-Mustern oder Links zu Ressourcen für Beispiele freuen.

19
Aaron

Ich würde empfehlen, vererbte Widgets weiter zu untersuchen. Der folgende Code zeigt, wie man sie zur asynchronen Aktualisierung von Daten verwendet:

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,
    );
  }
}
15
Matt S.

Ich bin wegen dieses Problems auf ein anderes Problem gestoßen Sie können es hier überprüfen .__ Die Lösung, die ich mir ausgedacht habe, ist etwas unordentlich. Ich habe eine separate Instanz-Dart-Seite erstellt und in jede Seite importiert.

 GoogleSignInAccount Guser = googleSignIn.currentUser;
 FirebaseUser Fuser;

Ich habe den Benutzer dort beim Login gespeichert und bei jedem StateWidget geprüft, ob es null ist 

  Future<Null> _ensureLoggedIn() async {

if (Guser == null) Guser = await googleSignIn.signInSilently();
if (Fuser == null) {
  await googleSignIn.signIn();
  analytics.logLogin();
}
if (await auth.currentUser() == null) {
  GoogleSignInAuthentication credentials =
  await googleSignIn.currentUser.authentication;
  await auth.signInWithGoogle(
    idToken: credentials.idToken,
    accessToken: credentials.accessToken,
  );
}

Dies ist mein alter Code, den ich in meiner aktuellen App aufgeräumt habe, aber ich habe diesen Code jetzt nicht zur Hand. Checken Sie einfach auf null Benutzer aus und melden Sie sich erneut an

Ich habe es auch für die meisten Firebase-Instanzen gemacht, weil ich mehr als 3 Seiten in meiner App habe und Inherited Widgets war einfach zu viel Arbeit

0
Prime