【问题标题】:Flutter secure routes with a flutter-fire authentication guard and avoid unnecessary rebuildsFlutter 安全路由与 Flutter-fire 身份验证保护并避免不必要的重建
【发布时间】:2021-05-13 18:21:41
【问题描述】:

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

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 包含我的 Flutter 应用的初始导航,并在开发过程中始终重置为索引零。

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

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

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

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

【问题讨论】:

    标签: flutter firebase-authentication stream-builder flutter-hotreload


    【解决方案1】:

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

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

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

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


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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-12-16
      • 2020-05-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-07
      • 2013-03-27
      • 2020-10-19
      相关资源
      最近更新 更多