Flutter 提供者和小部件生命周期

Posted

技术标签:

【中文标题】Flutter 提供者和小部件生命周期【英文标题】:Flutter provider and widget lifecycle 【发布时间】:2021-08-12 19:40:23 【问题描述】:

我有一个简单的流程:

一个 UserModel 实现 ChangeProvider ,它包装了用户的状态(如果它已登录并且实用程序让他登录/注销)。特别是注销看起来像:

void logout() 
   user = null;
   notifyListeners();

UserPage 小部件(其中包括):

class UserPage extends StatelessWidget 
     @override
     Widget build(BuildContext context) 
         // ... adding only relevant code

         // a text with the user first letter of the email
         Text(context.watch<UserModel>().user.email[0])

         // a logout button with the following onPressed method
         TextButton( \\ ...
             onPressed: ()  
               context.read<UserModel>().logout();  
               Navigator.pop(context); 
             
         )
     

我期待按下注销并弹出UserPage 小部件不会让颤振重建它。但事实并非如此,logout 方法中的notifyListeners() 使颤振重建小部件并触发NullPointerException(因为用户为空且无法访问电子邮件)。

我可以处理它(检查用户对象是否为 != null 但我想了解为什么会发生这种情况)。

假设pop 破坏了小部件是否正确?如果不是,我应该如何处理这种情况? 当用户注销时,我不想在内存中拥有这个小部件,也不想处理它的存在。我希望在用户登录时创建一个UserPage,并在注销后将其销毁

【问题讨论】:

【参考方案1】:

当您调用 logout 时,watch 在这行 Text(context.watch&lt;UserModel&gt;().user.email[0]) 将导致它所在的小部件重建。

你需要在你调用的push的回调中调用logout来推送这个页面。 pop 还可以发送值来告知成功或失败等条件。

所以应该是这样的:

Navigator.pushNamed(context, some_route).then(value) 
context.read<UserModel>().logout();  

回调中的value可以从pop返回,就像Navigator.of(context).pop(true);一样

这将确保 logout 仅在小部件弹出后才被调用。

如果您不喜欢回调,可以使用 async await 模式。

【讨论】:

谢谢,你的回答,然后谷歌搜索找到了这个(flutter.dev/docs/cookbook/navigation/returning-data),它有帮助!现在虽然屏幕弹出,然后注销过程(网络调用)开始,然后UserPage 被刷新。有没有办法确保在注销程序完成后显示UserPage 屏幕? 你明白了!假设您正在使用一个屏幕进行登录和用户页面,这些只是一个屏幕,某些状态决定了 UI 将显示什么。在这种情况下,您不需要弹出屏幕,因为通过调用 logout 完成重建就足够了 - 您只需要编写逻辑来处理基于用户状态显示的内容被登录在与否。如果你有单独的屏幕那么你可以使用popAndReplace,但绝对不要弹出,并推送同一个屏幕。

以上是关于Flutter 提供者和小部件生命周期的主要内容,如果未能解决你的问题,请参考以下文章

Flutter:小部件和导航的生命周期

Flutter:在从小部件树中删除时或在其生命周期结束时为小部件设置动画?

Flutter:在构造函数中调用 setState():_SharesListState#6c96a(生命周期状态:已创建,无小部件,未安装)

小程序的生命周期和小程序组件的生命周期

Flutter生命周期

4.Flutter生命周期与路由管理