flutter - 如何将 ChangeNotifier 与 Navigator 一起使用
问题描述
在我的应用程序中,我有一个模型来存储登录我的应用程序的用户。
class AuthenticationModel extends ChangeNotifier {
User _user;
User get user => _user;
void authenticate(LoginData loginData) async {
// _user = // get user from http call
notifyListeners();
}
void restoreUser() async {
//_user = // get user from shared prefs
notifyListeners();
}
}
该模型注册在小部件树的顶部:
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (_) => AuthenticationModel(),
child: MaterialApp(
title: 'My App',
initialRoute: '/',
routes: {
'/': (context) => PrehomeScreen(),
'/home': (context) => HomeScreen()
},
),
);
}
}
在小部件树的某个地方,我有一个调用 Model 的按钮:
child: Consumer<AuthenticationModel>(
builder: (context, authModel, child) {
return MyCustomButton(
text: 'Connect',
onPressed: () {
authModel.authenticate(...)
},
);
},
),
现在,我想在某个地方收听 上的更改以在模型中用户不为空时AuthenticationModel
触发 a 。Navigator.pushReplacmentNamed('/home')
我试图在 Prehome 的构建器中做到这一点:
class PrehomeScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Consumer<AuthenticationModel>(
builder: (context, authModel, child) {
if (authModel.user != null) {
Navigator.of(context).pushReplacementNamed("/home")
}
return Container(
child: // Prehome UI
);
},
);
}
}
但是这样做时我有一个错误:
════════ (2) Exception caught by widgets library ═══════════════════════════════════════════════════
setState() or markNeedsBuild() called during build.
The relevant error-causing widget was:
Consumer<AuthenticationModel> file:///Users/pierre.degand/Projects/cdc/course_du_coeur/lib/Prehome.dart:13:12
═══════════════════════════════════════════════════════════════════════════════
如何设置这样的侦听器?在这样的模型更改上触发导航是一种好习惯吗?
谢谢
编辑:我找到了一种方法来完成这项工作。Consumer
我没有在 PrehomeScreen 构建器中使用,而是使用了以下代码:
class PrehomeScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
Provider.of<AuthenticationModel>(context).addListener(() {
Navigator.of(context).pushReplacementNamed("/home");
});
return Container(
child: // UI
);
}
}
它工作正常,导航在模型更改时执行。但是控制台有错误信息(打印3次):
════════ (4) Exception caught by foundation library ════════════════════════════════════════════════
Looking up a deactivated widget's ancestor is unsafe.
════════════════════════════════════════════════════════════════════════════════════════════════════
该应用程序不会崩溃,所以现在,我可以接受。我仍然想知道这是否是一个好方法。
解决方案
void main() {
Provider.debugCheckInvalidValueType = null;
return runApp(
Provider(
create: (_) => AuthenticationModel(),
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
final navigatorKey = GlobalKey<NavigatorState>();
Provider.of<AuthenticationModel>(context).addListener(() {
final authModel = Provider.of<AuthenticationModel>(context);
if (authModel.user != null) {
navigatorKey.currentState.pushReplacementNamed("/home");
}
});
return MaterialApp(
navigatorKey: navigatorKey,
title: 'My App',
initialRoute: '/',
routes: {
'/': (context) => PrehomeScreen(),
'/home': (context) => HomeScreen()
},
);
}
}
推荐阅读
- android - 片段内带有缓存的 Webview
- c# - “IEntityType”不包含“关系”的定义
- python - 使用牛顿拉夫森方法求根
- r - 应用函数 R 中的 if-else 语句
- arrays - 如何在 Tiled 中使用 userData 进行碰撞?(LigGDX)
- javascript - Discord.js 角色/分级系统
- c++ - 如何从 C++ 中的其他函数/方法调用运算符重载函数?
- excel - Excel VBA,列列表中包含“IS”和“S”的第一个单元格中的颜色
- ios - 是否可以仅将视图控制器的一部分嵌入容器视图中?
- python - 我想创建一个列表,将所有奇数替换为字符串