1 背景介绍

1.1 声明式ui

声明式UI其实并不是近几年的新技术,但是近几年声明式UI框架非常的火热。单说移动端,跨平台方案有:RN、Flutter。iOS原生有:SwiftUI。android原生有:compose。可以看到声明式UI是以后的前端发展趋势。而状态管理是声明式UI框架的重要组成部分。

1.2 声明式UI框架的状态

在移动端之前的命令式UI框架,没有状态的概念。每个控件其实都是无状态的,我们要更新UI需要手动的去set。命令式UI引入状态的概念,状态可以理解为订阅了控件所依赖数据的变化,当一个控件依赖的数据发生变化时,自动刷新UI展示。最大的优势就是可以很方便的做到UI和逻辑的解耦。

2 provider状态管理

2.1 使用方式

定义一个页面如下:

实现功能,当点击“按钮”的时候,更新“你好”这个组件

页面部分代码实现(基于StatelessWidget实现):

model部分实现:

2.2 问题和不足

点击“按钮”的时候查看页面刷新,发现下表罗列的Widget都执行了刷新操作,使用Selector虽然被包裹的内容没有刷新,但是需要进行校验操作。

2.2.1 控件刷新

2.2.2 问题分析

  1. 使用不太灵活,想要消费事件刷新UI必须有顶层的Provider提供model,在一些复杂场景可能会增加逻辑复杂度
  2. 状态刷新,不能实现最小粒度的管理
  3. 代码不够简洁

3 新的状态管理方式实践

3.1 使用方式

实现同样的上述页面逻辑,代码如下(同样基于StatelessWidget实现):

首先不需要依赖外部的provider提供Model,任何想要独立刷新的区域使用TosObWidget控件包裹即可,使用比较灵活,我们可以把TosObWidget插入到任何我们想要的位置(包括provider内),代码逻辑比较简洁

model实现:

model的实现更加简洁,不需要继承ChangeNotifier,所以可以把状态数据定义在任何我们想要的地方,使用.tos扩展属性返回一个包含默认值的RxObj对象,当我们使用set方法更改RxObj的value的时候,通知依赖此对象的TosObWidget区域进行刷新,例:我们点击按钮的时候,_model.textA.value = “你好${_model.i++}”,执行后就会刷新依赖textA的TosObWidget(() => Text(_model.textA.value))区域

查看刷新状态(与provider对比):

对比发现TosObWidget这种方式,只有依赖的数据发生变化的TosObWidget才会更新状态,可以实现状态刷新粒度最小化,提高性能

3.2 设计思路

3.2.1 TosObWidget

首先是使用入口,定义一个TosObWidget控件,入参为build函数,返回widget,每个TosObWidget就是一个可独立进行状态刷新的区域

TosObWidget控件的实现如下:

TosObWidget的build函数为重载的其父类_ObzWidget的build函数,最终会被_ObzWidget的_ObzState调用,_ObzWidget的实现如下:

接下来查看_ObzState的实现,主要逻辑都在这个类进行实现,这里贴出所有的代码(注意框起来的逻辑):

3.2.2 TosObWidget逻辑分析

  1. 首先_ObzState依赖一个RxObserver _observer变量
  2. RxObserver _observer这个 变量持有了_updateUI()这个方法,最终会通过这个方法刷新TosOBWidget的状态
  3. 当TosObWidget执行build的时候,会通过一个静态变量RxObserver.proxy把_observer共享出去
  4. 这样TosObWidget包裹的内容,使用RxObj的getValue的时候会拿到被共享的_observer,这时建立RxObj和TosObWidget的联系
  5. 联系建立后,重置共享变量RxObserver.proxy
  6. 这样在RxObj的value执行set方法时,会调用到与其绑定的TosObWidget的_updateUI()这个函数

3.2.3 RxObj的实现

如下贴出RxObj的value的get和set函数:

  1. 当执行RxObj的value的get方法时,代码如下,拿到 RxObserver的静态成员变量proxy,类型为RxObserver(即为上一步TosObWidget共享出来的_observer)
  2. 判断RxObserver.proxy不为空,且没有被添加到_observers列表( List _observers),则添加
  3. 当执行RxObj的value的set方法时,校验value是否与当前的value值相同,且判断是否是首次创建(首次创建不会执行状态刷新)
  4. 校验完成后则赋值执行refresh()函数,更新TosObWidget的状态

refresh()函数的实现如下:

observer.update()函数即为执行与Rxobj关联的TosObWidget的_updateUI()函数:

看下RxObserver的实现:

注意框起来的逻辑,update函数即上面_ObzState的_updateUI()函数的引用

至此整个实现流程已经贯通了,接下来看下如何使用:

1)通过.tos扩展属性定义RxObj变量:

2).tos扩展属性的实现如下:

3)如果要创建一个默认值为空的,RxObj实例,使用如下方式:

此时如果我们使用RxObj的setValue方法,就会刷新依赖它的所有TosObWidget控件,如果有些情况下,没有调用setValue方法,但是需要刷新状态,可手动调用refresh()方法,实现如下:

至此,就完成了TosObWidget控件的状态刷新

4 总结

注:基于本文示例的功能逻辑进行对比

作者:京东物流 张俊飞

来源:京东云开发者社区

Flutter状态管理新的实践的更多相关文章

  1. Flutter 状态管理- 使用 MobX

    文 / Paul Halliday, developer.school 创始人 众所周知,状态管理是每个软件项目都需要持续迭代更新的方向.它并不是一个「一次性」的工作, 而需要不断确保你遵循的最佳实践 ...

  2. Flutter | 状态管理特别篇——Provide

    前言 今天偶然发现在谷歌爸爸的仓库下出现了一个叫做flutter-provide的状态管理框架,2月8日才第一次提交,非常新鲜.在简单上手之后感觉就是一个字--爽!所以今天就跟大家分享一下这个新的状态 ...

  3. Flutter 状态管理之BLoC

    在正式介绍 BLoC之前, 为什么我们需要状态管理.如果你已经对此十分清楚,那么建议直接跳过这一节.如果我们的应用足够简单,Flutter 作为一个声明式框架,你或许只需要将 数据 映射成 视图 就可 ...

  4. Flutter状态管理之provide和provider的使用区别

    说道状态管理不得不说谷歌的亲自开发的两款状态管理Widget:第一个是provide,第二个是provider. 这两个的区别就是一个出来的早,现在好像没整么更新了.第二个是2019才出来的目前的版本 ...

  5. Flutter状态管理Provider,简单上手

    在之前的文章中介绍了 Google 官方仓库下的一个状态管理 Provide.乍一看这俩玩意可能很容易就被认为是同一个东西,仔细一看,这不就差了一个字吗,有什么区别呢. 首先,你要知道的最大的一个区别 ...

  6. Flutter 状态管理 flutter_Provide

    项目的商品类别页面将大量的出现类和类中间的状态变化,这就需要状态管理.现在Flutter的状态管理方案很多,redux.bloc.state.Provide. Scoped Model : 最早的状态 ...

  7. Flutter实战视频-移动电商-24.Provide状态管理基础

    24.Provide状态管理基础 Flutter | 状态管理特别篇 —— Provide:https://juejin.im/post/5c6d4b52f265da2dc675b407?tdsour ...

  8. Flutter移动电商实战 --(24)Provide状态管理基础

    Flutter | 状态管理特别篇 —— Provide:https://juejin.im/post/5c6d4b52f265da2dc675b407?tdsourcetag=s_pcqq_aiom ...

  9. (转)flutter 新状态管理方案 Provide (一)-使用

    flutter 新状态管理方案 Provide (一)-使用     版权声明:本文为博主原创文章,基于CC4.0协议,首发于https://kikt.top ,同步发于csdn,转载必须注明出处! ...

  10. React 新 Context API 在前端状态管理的实践

    本文转载至:今日头条技术博客 众所周知,React的单向数据流模式导致状态只能一级一级的由父组件传递到子组件,在大中型应用中较为繁琐不好管理,通常我们需要使用Redux来帮助我们进行管理,然而随着Re ...

随机推荐

  1. 搭建DHCP服务,实现自动分配地址

    DHCP实现原理 DHCP定义 DHCP(Dynamic Host Configuration Protocol,动态主机配置协议)是一个局域网的网络协议,使用UDP协议工作.它是一种流行的Clien ...

  2. C++/Qt网络通讯模块设计与实现(总结)

    至此,C++/Qt网络通讯模块设计与实现已分析完毕,代码已应用于实际产品中. C++/Qt网络通讯模块设计与实现(一) 该章节从模块的功能需求以及非功能需求进行分析,即网络通讯模块负责网络数据包的发送 ...

  3. 从零开始学Vue(一)—— Vue.js 入门

    概述 vue.js作为现在笔记热门的JS框架,使用比较简单易上手,也成为很多公司首选的JS框架. 但是对于初学者可能学起来有些麻烦,所以推出<从零开始学Vue>系列博客,本系列计划推出19 ...

  4. Callback详解

    Callbacks Callback Registration 在 Rails 中,回调(Callbacks)是一种在模型对象的生命周期中执行特定代码的机制.回调可以在模型对象的创建.更新.删除等操作 ...

  5. Vue中插槽的使用

    1.作用:让父组件可以向子组件指定位置插入html结构,也是一种组件间通信的方式,适用于 父组件 ===> 子组件 . 2.分类:默认插槽.具名插槽.作用域插槽 3.使用方式: ①默认插槽    ...

  6. vue中父组件给子组件传值的方法

    顺序............................................. -------------列表组件,注册组件.调用使用组件----------------- 1,子组件 ...

  7. 当 SQL Server(mssql-jdbc) 遇上 BigDecimal → 精度丢失,真坑!

    开心一刻 中午和哥们一起喝茶 哥们说道:晚上喝酒去啊 我:不去,我女朋友过生日 哥们瞪大眼睛看着我:你有病吧,充气的过什么生日 我生气到:有特么生产日期的好吧 需求背景 系统对接了外部系统,调用外部系 ...

  8. String、StringBuilder、StringBuffer使用场景

    String:加了final修饰,长度不可变,每次修改会创建新String:操作少量数据或者不需要操作数据时使用. StringBuilder:长度可变,线程不安全:在需要频繁操作数据且不需要考虑线程 ...

  9. mysql 结合python一些日常写法

    python sql语句in写法 sql = "SELECT * FROM user WHERE name in ({})".format(','.join(["'%s' ...

  10. 2020-10-02:golang如何写一个插件?

    福哥答案2020-10-02:#福大大架构师每日一题#简单回答:buildmode=plugin plugin.Openp.Lookup [中级回答:](https://www.zhihu.com/q ...