Использование 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 {}
Если вы протестируете приложение, вы увидите, что управление состоянием работает между входом в систему и домашней страницей, как и ожидалось с кодом, но как только вы перейдете на второй экран с домашней страницы и нажмете кнопку выхода, состояние изменится в приложении, но дерево виджетов не обновляется.
statelessWidget
. Вместо этого используйтеstatefulWidget
. - person John Joe   schedule 16.12.2020