问题描述
我目前面临一个问题,我将路由到身份验证防护视图作为我的默认路由。 我的身份验证守卫视图:
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
中的流并在用户更改时推送命名路由 - 上面提供的解决方案
如果您需要更多信息、代码、控制台打印或其他支持我,请给我留言。谢谢!
解决方法
我能够自己修复它。对于任何感兴趣的人,这是过程:
stream
是决定 AsyncStreamWidget
是否重建其子项的枢轴元素。因此,我确实通过打印其 stream
属性来检查 hashCode
是否在热重新加载时发生了变化(是的,它确实发生了变化)。
随后,我确实将 ViewAuthGuard
更改为 StatefulWidget
,并使用 didChangeDependencies
方法将 stream
存储在状态中。
(我还开始在 initState
方法中实例化小部件并将它们存储在状态中,以便它们只创建一次。)
EDIT 而且我应该提到我的 ViewAuthGuard
没有依赖项。所以不会因为依赖关系的改变而重建。