0

我目前面临一个问题,我将路由到身份验证保护视图作为我的默认路由。我的身份验证保护视图:

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.

我用 ThemeProvider ChangeNotifier 包装了我的 Material 应用程序(以防出现问题)。

我的问题是下面的所有小部件ViewAuthGuard都在重建并且它们的状态被重置。我在开发时会遇到这种情况。当发生热重载时,所有子节点都将重建。TabsScreenView包含我的颤振应用程序的初始导航,并在开发过程中始终重置为索引零。

问题:此时如何避免不必要的重新加载?

到目前为止我测试的内容:

  • TabsScreenView用 FutureBuilder / StreamBuilder 包装了我的命名路由并将其设置为默认路由(Flutter 中的 Route Guards
  • 在用户更改时监听流didComponentUpdate并推送命名路由
  • 上面提供的解决方案

如果您需要更多信息、代码、控制台打印或其他支持我,请给我留言。谢谢!

4

1 回答 1

0

我能够自己修复它。对于任何感兴趣的人,这是一个过程:

stream是决定是否AsyncStreamWidget重建其子元素的枢轴元素。所以我确实通过打印它的属性来检查stream热重载是否发生了变化(是的,它确实发生了变化)。hashCode

随后,我确实将 my 更改ViewAuthGuard为 aStatefulWidget并使用该didChangeDependencies方法将其存储stream在状态中。

(我还开始在方法中实例化小部件initState并将它们存储在状态中,以便它们只创建一次。)


编辑我应该提到我ViewAuthGuard没有依赖关系。所以它不会因为依赖关系的变化而重建。

于 2021-02-13T07:59:42.963 回答