Flutter 使用 Provider 管理状态的实践记录
date
May 24, 2021
slug
practice-record-using-provider-in-flutter-to-manage-state
status
Published
summary
通过全局的 Provider 管理文章的数据,当发生更新时,直接 Rebuild 对应的 Widget 即可
tags
Flutter
type
Post
一、背景二、示例一:文章流 & 交互2.1 建立 Model2.2 列表构建2.2.1 注册 Model2.2.2 如何实现列表构建(数据获取和消费)2.3 已读和收藏2.4 Hot Reload 带来的一些问题三、示例二:Tabbar 状态更新3.1 定义 Model 属性3.2 状态获取和更新3.3 切换 Tab 时的一些影响
一、背景
在做一个自用的 TinyTiny RSS 阅读器,其中将文章列表部分拆分成了三个模块以减少嵌套。
同时,针对于单篇文章需要提供点击文章和修改标题颜色、标记已读和未读、收藏和取消收藏的功能;因此涉及到子组件修改父组件的参数,所以需要在父组件提供一个方法用于修改,大致代码如下:
- UnreadPage:页面父组件
- FeedItem:Feed 流子组件
- ArticleItem:article 流子组件
可以看到这样的结构比较繁琐,而且必须要使用 StatefulWidget 用于更新状态;
因此,想到通过全局的
Provider
管理文章的数据,当发生更新时,直接 Rebuild
对应的 Widget
即可。二、示例一:文章流 & 交互
2.1 建立 Model
该 Model 主要提供更新文章数据,更新阅读和星标状态等功能。
2.2 列表构建
这部分主要是如何去使用 Provider 提供的数据:
2.2.1 注册 Model
这个是正常的注册方式,但是有时候会有很多个 Model 需要处理,因此可以处理成这样:
2.2.2 如何实现列表构建(数据获取和消费)
状态获取有三种方式:
- Provider.of 方法:
Provider.of<Model>(context, listen: false)
- Consumer Widget:
Consumer(builder: (context, Model provider, _) => Text('Value: ${provider.data}'))
- Selector Widget:
每一次数据更新后,对应使用相关数据的 Widget 都会触发 Rebuild,而上述三种中后两种都可以实现精确地控制刷新粒度;
而 Selector 尤其适用于列表构建、针对单条数据单独触发 UI 刷新和管理是否需要刷新 UI,示例:
其中,当
shouldRebuild
设置为 false
,则代表就算状态更新了该列表项也不会触发 UI 刷新;shouldRebuild
默认为 prev ≠ next
。另外,可以进一步优化列表,在外面包一层
Selector
,并且设置 shouldRebuild: (prev, next) => false
,这样就禁止了因为状态更新导致整个列表重新刷新 UI 的可能。2.3 已读和收藏
针对单篇文章的已读和收藏状态刷新也是一样,通过 Selector 更新:
2.4 Hot Reload 带来的一些问题
另外需要注意的一点是,有时候 Model 注册使用了
ChangeNotifierProvider.value
会导致调试时热更新让状态数据丢失。解决方案是使用下述方式注册
三、示例二:Tabbar 状态更新
3.1 定义 Model 属性
3.2 状态获取和更新
3.3 切换 Tab 时的一些影响
目前默认情况下切换 Tab 会导致前一页的状态丢失,因此需要使用一些方式进行处理:
在需要保持状态的页面添加
with AutomaticKeepAliveClientMixin
,同时添加bool _wantKeepAlive = true
这样,从该页面切换出去,就不会丢失状态了。
但是,与此同时还带来一个问题,有时候我们需要更新页面的状态用以展示新的数据,如果一直强制保持,会导致页面无法展示出新的数据。
针对这个问题,可以通过定义
wantKeepAlive
,并通过方法updateKeepAlive
来修改当前页面是否需要保持状态。