В настоящее время я сталкиваюсь с проблемой, когда я использую представление защиты аутентификации в качестве маршрута по умолчанию. Мой вид защиты аутентификации:

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

import '../models/user.dart';
import '../services/services.module.dart';
import '../widgets/common/async_stream.dart';
import 'landing_screen/landing_screen.dart';
import 'tabs_screen/tab_screen.dart';

/// The [ViewAuthGuard] decides whether to display the [LandingScreenView] or the [TabsScreenView].
class ViewAuthGuard extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print('ViewAuthGuard build called: $context');
    FirebaseAuthService authService = Provider.of<AuthService>(context, listen: false);

    return AsyncStreamWidget<User>(
      stream: authService.onAuthStateChanged,
      child: (User user) => TabsScreenView(),
      emptyWidget: LandingScreenView(),
      loadingWidget: null,
      errorWidget: null,
    );
  }
}

И мой AsyncStreamWidget:

import 'package:flutter/material.dart';

import '../../../models/base_model.dart';
import '../../error/future_error.dart';
import '../../loading.dart';

class AsyncStreamWidget<T extends BaseModel> extends StatelessWidget {
  final Stream<T> stream;
  final T initialData;

  Widget _loading;
  Widget _empty;
  Widget Function(Object) _error;
  Widget Function(T) child;

  AsyncStreamWidget({
    @required this.stream,
    @required this.child,
    this.initialData,
    Widget loadingWidget,
    Widget emptyWidget,
    Widget Function(Object) errorWidget,
  }) {
    if (loadingWidget == null) {
      _loading = Loading();
    } else {
      _loading = loadingWidget;
    }

    if (errorWidget == null) {
      _error = (Object error) => FutureErrorWidget(error: error);
    } else {
      _error = errorWidget;
    }

    if (emptyWidget == null) {
      _empty = Center(child: Text('No data available.'));
    } else {
      _empty = emptyWidget;
    }
  }

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<T>(
      initialData: initialData,
      stream: stream,
      builder: (_, AsyncSnapshot<T> snapshot) {
        switch (snapshot.connectionState) {
          case ConnectionState.waiting:
            return _loading;
            break;
          case ConnectionState.active: // check if different behavior is needed for active and done
          case ConnectionState.done:
            // error state
            if (snapshot.hasError) {
              // todo more throughout error checking and specialized error widget
              return _error(snapshot.error);
            }

            // data state
            if (snapshot.hasData) {
              T data = snapshot.data;
              return child(data);
            }

            // empty state
            return _empty;
          case ConnectionState.none:
          default:
            print('E: Received Future [$stream] was null or else.');
            return _error('Unknown error.');
        }
      },
    );
  }
}

FirebaseAuthService оборачивает auth.FirebaseAuth.instance. Мой поток построен следующим образом:

User _userFromFirebase(auth.User user) {
  if (user == null) {
    return null;
  }
  return User(
    uid: user.uid,
    email: user.email,
    displayName: user.displayName,
    photoUrl: user.photoURL,
  );
}

@override
Stream<User> get onAuthStateChanged => _firebaseAuth.authStateChanges().map(_userFromFirebase);

В настоящее время я предоставляю все свои услуги сверх ViewAuthGuard.

Я обернул свое приложение Material с помощью ThemeProvider ChangeNotifier (на случай, если это может быть проблемой).

Моя проблема в том, что все виджеты ниже ViewAuthGuard перестраиваются и их состояние сбрасывается. Это происходит со мной во время разработки. Когда происходит горячая перезагрузка, все дочерние элементы восстанавливаются. TabsScreenView содержит начальную навигацию для моего приложения flutter и всегда сбрасывается до нуля во время разработки.

Вопрос: Как мне избежать ненужных перезагрузок на этом этапе?

Что я тестировал до сих пор:

  • Я заключил свой именованный маршрут для TabsScreenView с помощью FutureBuilder / StreamBuilder и установил его в качестве маршрута по умолчанию (Route Охранники во флаттере)
  • Прослушивание потока в didComponentUpdate и отправка именованных маршрутов при изменении пользователя
  • Решение, представленное выше

Пожалуйста, напишите мне комментарий, если вам нужна дополнительная информация, код, распечатки консоли или что-то еще, чтобы поддержать меня. Спасибо!

0
tahesse 10 Фев 2021 в 06:29

1 ответ

Лучший ответ

Сам смог починить. Для всех, кого это интересовало, это был процесс:

stream - это стержневой элемент, который решает, перестраивает ли AsyncStreamWidget свой дочерний элемент или нет. Поэтому я проверил, изменился ли stream при горячих перезагрузках, распечатав его атрибут hashCode (и да, он изменился).

Впоследствии я изменил свой ViewAuthGuard на StatefulWidget и использовал метод didChangeDependencies для сохранения stream в состоянии.

(Я также начал создавать экземпляры виджетов в методе initState и сохранять их в состоянии, чтобы они создавались только один раз.)


РЕДАКТИРОВАТЬ И я должен упомянуть, что мой ViewAuthGuard не имеет зависимостей. Так что он не перестраивается из-за изменения зависимостей.

0
tahesse 13 Фев 2021 в 08:57