【发布时间】:2020-12-16 16:32:18
【问题描述】:
使用 Riverpod + StateNotifier,但我认为其他提供商也存在同样的问题。
我有一个身份验证 StateNotifier 类和 StateNotifierProvider 并将 MaterialApp 小部件包装到 Riverpod Consumer 中,以便在用户不再经过身份验证时重建完整的应用程序/小部件树。
当我使用 pushReplacementNamed 导航到第三页并更新 authenticationStateNotifierProvider 的状态时,我可以看到包装应用程序的消费者的构建方法被触发并且状态被更新(打印(状态))但是主页页面和小部件树不会重建。
具有 3 个屏幕的示例应用程序:
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/all.dart';
void main() {
runApp(ProviderScope(child: MyApp()));
}
class MyApp extends ConsumerWidget {
@override
Widget build(BuildContext context, ScopedReader watch) {
final state = watch(authenticationNotifier.state);
print(state);
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: state is Unauthenticated ? LoginScreen() : HomeScreen(),
onGenerateRoute: (RouteSettings settings) {
if (settings.name == '/second')
return MaterialPageRoute(builder: (_) => SecondScreen());
else
return MaterialPageRoute(builder: (_) => HomeScreen());
},
);
}
}
class HomeScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('HomeScreen'),
),
body: Column(
children: [
MaterialButton(
child: Text('Logout'),
onPressed: () => context.read(authenticationNotifier).toggle(),
),
MaterialButton(
child: Text('Second'),
onPressed: () => Navigator.pushReplacementNamed(
context,
'/second',
),
),
],
),
);
}
}
class SecondScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('SecondScreen'),
),
body: MaterialButton(
child: Text('Logout'),
onPressed: () => context.read(authenticationNotifier).toggle(),
),
);
}
}
class LoginScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('LoginScreen'),
),
body: MaterialButton(
child: Text('Login'),
onPressed: () => context.read(authenticationNotifier).toggle(),
),
);
}
}
// Controller.
final authenticationNotifier =
StateNotifierProvider((ref) => AuthenticationNotifier());
class AuthenticationNotifier extends StateNotifier<AuthenticationState> {
AuthenticationNotifier() : super(Unauthenticated());
void toggle() {
state = state is Unauthenticated ? Authenticated() : Unauthenticated();
}
}
// State.
abstract class AuthenticationState {}
class Authenticated extends AuthenticationState {}
class Unauthenticated extends AuthenticationState {}
如果您测试应用程序,您将看到登录和主页之间的状态管理与代码预期的一样,但是一旦您从主页导航到第二个屏幕并按下注销按钮,状态就会在应用 widged 但小部件树未更新。
【问题讨论】:
-
因为你使用
statelessWidget。请改用statefulWidget。 -
我使用 statelessWidget 是因为我使用 Consumer 来重建小部件并管理状态。实际上,如果我在身份验证状态更改时调试构建方法正在执行。问题是 MaterialApp 没有使用新的主页小部件重新创建小部件树。
-
您的 authenticationStateNotifierProvider 的状态是什么类型? (state is Authenticated) 看起来很奇怪,不像枚举,所以只是想知道这是否是问题所在。即,您的条件写得是否正确?
-
我已经用工作示例代码编辑了这个问题来演示这个问题。在 pubspec 中使用 state_notifier 和 flutter_riverpod。示例应用也在github.com/abibiano/riverpod_test