类似React/Vue的状态管理
以下是管理状态的最常见的方法:
* Widget 管理自己的状态。
* Widget 管理子 Widget 状态。
* 混合管理(父 Widget 和子 Widget 都管理状态)。
一般的原则是:如果状态是组件私有的,则应该由组件自己管理;如果状态要跨组件共享,则该状态应该由各个组件共同的父元素来管理。
下面是官方给出的一些原则可以帮助你做决定:
* 如果状态是用户数据,如复选框的选中状态、滑块的位置,则该状态最好由父 Widget 管理。
* 如果状态是有关界面外观效果的,例如颜色、动画,那么状态最好由 Widget 本身来管理。
* 如果某一个状态是不同 Widget 共享的则最好由它们共同的父 Widget 管理。
### 全局状态管理
当应用中需要一些跨组件(包括跨路由)的状态需要同步时,上面介绍的方法便很难胜任了。比如,我们有一个设置页,里面可以设置应用的语言,我们为了让设置实时生效,我们期望在语言状态发生改变时,App中依赖应用语言的组件能够重新 build 一下,但这些依赖应用语言的组件和设置页并不在一起,所以这种情况用上面的方法很难管理。这时,正确的做法是通过一个全局状态管理器来处理这种相距较远的组件之间的通信。目前主要有两种办法:
1. 实现一个全局的事件总线,将语言状态改变对应为一个事件,然后在APP中依赖应用语言的组件的initState 方法中订阅语言改变的事件。当用户在设置页切换语言后,我们发布语言改变事件,而订阅了此事件的组件就会收到通知,收到通知后调用setState(...)方法重新build一下自身即可。
2. 使用一些专门用于状态管理的包,如 Provider、Redux,读者可以在 pub 上查看其详细信息。
## 跨组件状态共享(Provider)
provider 原理图
![](https://img.kancloud.cn/6e/02/6e0251132f18870a9e72465f4d98b8f6_500x277.png)
Model变化后会自动通知ChangeNotifierProvider(订阅者),ChangeNotifierProvider内部会重新构建InheritedWidget,而依赖该InheritedWidget的子孙Widget就会更新。
我们可以发现使用Provider,将会带来如下收益:
1. 我们的业务代码更关注数据了,只要更新Model,则UI会自动更新,而不用在状态改变后再去手动调用setState()来显式更新页面。
2. 数据改变的消息传递被屏蔽了,我们无需手动去处理状态改变事件的发布和订阅了,这一切都被封装在Provider中了。这真的很棒,帮我们省掉了大量的工作!
3. 在大型复杂应用中,尤其是需要全局共享的状态非常多时,使用Provider将会大大简化我们的代码逻辑,降低出错的概率,提高开发效率。
Provider (opens new window)& Scoped Model(opens new window) 这两个包都是基于InheritedWidget的,原理相似
Redux(opens new window) 是Web开发中React生态链中Redux包的Flutter实现
MobX(opens new window) 是Web开发中React生态链中MobX包的Flutter实现
BLoC(opens new window) 是BLoC模式的Flutter实现