Flutter高内聚组件怎么做?闲鱼闲鱼打造开源高效方案!

栏目: 软件资讯 · 发布时间: 4年前

内容简介:redux对于前端的同学来说是一个比较熟悉的框架了,fish_redux借鉴了redux单项数据流思想。在flutter上说到redux,大家可能第一反应会类比到react上的react_redux。在react_redux中有个重要的概念——简单得说,那么fish_redux中的connector是做什么的呢?为什么说connector解决了组件内聚的问题?我们应该如何理解它的设计呢?

redux对于前端的同学来说是一个比较熟悉的框架了,fish_redux借鉴了redux单项数据流思想。在flutter上说到redux,大家可能第一反应会类比到react上的react_redux。在react_redux中有个重要的概念—— connect

connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])

简单得说, connect 允许使用者从Redux store中获取数据并绑定到组件的props上,可以dispatch一个action去修改数据。

那么fish_redux中的connector是做什么的呢?为什么说connector解决了组件内聚的问题?我们应该如何理解它的设计呢?

connector in fish_redux

尽管都起到了连接的作用,但fish_redux与react_redux在抽象层面有很大的不同。

fish_redux本身是一个flutter上的应用框架,建立了自己的component体系,用来解决组件内的高内聚和组件间的低耦合。从connector角度来说,如何解决内聚问题,是设计中的重要考量。

fish_redux自己制造了 Component 树, Component 聚合了state和dispatch,每一个子 Component 的state通过 connector 从父 Component 的state中筛选。如图所示:

Flutter高内聚组件怎么做?闲鱼闲鱼打造开源高效方案!

可以看到,fish_redux的connector的主要作用把父子 Component 关联起来,最重要的操作是 filter 。state从上之下是一个严谨的树形结构,它的结构复用了 Component 的树形结构。类似一个漏斗形的数据管道,管理数据的分拆与组装。它表达了如何组装一个 Component

而对于react_redux来说,它主要的作用在于把react框架和redux绑定起来,重点在于如何让React component具有Redux的功能。

Flutter高内聚组件怎么做?闲鱼闲鱼打造开源高效方案!

从图中可以看到,react_redux和React是平行的结构,经过 mapStateToProps 后的state也不存在严谨的树形结构,即对于一个React component来说,它的state来自于Redux store而不是父component的state。从框架设计的角度来说,react_redux最重要的一个操作就是 attach

源码分析

说完概念,我们从源码的角度来看看fish_redux中的connector是如何运作的,以fish_redux提供的example为例。

class ToDoListPage extends Page<PageState, Map<String, dynamic>> {ToDoListPage(): super(...dependencies: Dependencies<PageState>(adapter: ToDoListAdapter(),slots: <String, Dependent<PageState>>{'report': ReportConnector() + ReportComponent()}),...);}
复制代码

在ToDoListPage的构造函数中,向父类构造传递了一个 Dependencies 对象,在构造 Dependencies 时,参数 slots 中包含了名叫"report"的item,注意这个item的生成,是由一个 ReportConnector + ReportComponent 产生的。

从这里我们得出一个简单却非常重要的结论:

在fish_redux中,一个Dependent = connector + Component 。

Dependent 代表页面拼装中的一个单元,它可以是一个 Component (通过buildComponent函数产生),也可以是一个 Adapter (由buildAdapter函数产生)。这样设计的好处是,对于View拼装操作来说, Dependent 对外统一了API而不需要透出更多的细节。

根据上面我们得出的结论, connector 用来把一个更小的 Component 单元链接到一个更大的 ComponentAdapter 上。这与我们之前的描述相符合。

connector到底是什么?

知道了 connector 的基本作用,我们来看一下它到底链接了哪些东西以及如何链接。

先来看一下ReportConnector类的定义:

class ReportConnector extends ConnOp<PageState, ReportState>
复制代码

ReportConnector 继承了 ConnOp 类,所有 connector 的操作包括**+**操作,都来自于 ConnOp 类。

Flutter高内聚组件怎么做?闲鱼闲鱼打造开源高效方案!

set/get

既然是数据管道,就会有获取和放置。

set 函数的入参很好得表达了 TP 的意思,即把一个 P 类型的 subState 合并到 T 类型的 state 中。

再回头看 get 函数,就很好理解了, get 函数表达的就是如何从 T 类型的 state 中获取 P 类型的 subStateDependent 使用。

operator +

+ 操作符的重载是我们最初看到connector作用的地方,也是connector发挥作用的入口。

LogicComponentAdapter 的父类,它表示页面组装元素的逻辑层,里面包含了 reducer / effect / higherEffect 等与逻辑相关的元素以及它的组装过程。

operator + 调用了 createDependent 函数,接着会调用到 _Dependent 类的构造函数,这里将 logicconnector 放入 _Dependent 内部,在后面fish_redux对 Component 组装的过程中,connector会随着外部对 _Dependent 中函数的调用发挥作用。

connector正式登场

铺垫了这么多,是该connector正式发挥作用的时候了。

get

我们以 Component 为例,会调用到 _DependentbuildComponent 函数:

Widget buildComponent(MixedStore<Object> store, Get<T> getter) {final AbstractComponent<P> component = logic;return component.buildComponent(store, () => connector.get(getter()));}
复制代码

这里的 logic 实际就是一个 Component 对象,在调用 ComponentbuildComponent 函数的时候,使用 get 函数从一个大的父state中获取到当前 Component 需要的数据集。接下去,这个变换后的子state将被用在例如 ViewBuilderRedcuer 函数中。

这是connector在数据获取上的作用。

set

还是在 _Dependent 类里面,看 createSubReducer 函数:

SubReducer<T> createSubReducer() {final Reducer<P> reducer = logic.reducer;return reducer != null ? connector.subReducer(reducer) : null;}
复制代码

首现从一个 Logic (这里实际上是一个 Component )对象中获取到外部设置进来的 reducer ,接着调用 subReducer 返回一个 SubReducer 对象。 SubReducer 是一个被wrap后的 Reducer。

subReducer 的实现在 MutableConn 中, ConnOp 继承了 MutableConn 类,也获得了这个能力。

SubReducer<T> subReducer(Reducer<P> reducer) {return (T state, Action action, bool isStateCopied) {final P props = get(state);if (props == null) {return state;}final P newProps = reducer(props, action);final bool hasChanged = newProps != props;final T copy = (hasChanged && !isStateCopied)? _clone<T>(state) : state;if (hasChanged) {set(copy, newProps);}return copy;};}
复制代码

它首现通过 get 函数得到一个变换后的数据集 props ,接着调用原始的 reducer 函数进行逻辑处理,这里有一个优化也是 SubReducer 的作用,如果数据集在经过 reducer 处理之后发生了变化,并且state已经被copy过一次了(isStateCopied==true),就直接把 newProps 通过 set 函数更新到state中去。(这个优化可以防止多个子state发生变化的时候父state被拷贝多次)。

至此,connector在数据更新上的作用也体现出来了。

ReportConnector

最后,就好理解ReportConnector的实现了:

class ReportConnector extends ConnOp<PageState, ReportState> {@overrideReportState get(PageState state) {final ReportState reportState = ReportState();reportState.total = state.toDos.length;reportState.done =state.toDos.where((ToDoState tds) => tds.isDone).toList().length;return reportState;}@overridevoid set(PageState state, ReportState subState) {}}
复制代码

很明显的,在 get 函数中, ReportStatePageState 中获得了total/done字段。

总结

闲鱼客户端的详情页完全使用了fish_redux进行了重构,通过高内聚的 Component+connector 形式,使得 Component 可以被大量复用,很好得支持了5种类型的详情页。未来我们会基于fish_redux强大的扩展能力制作更多组件来满足不同业务对于框架的需求。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Imperfect C++中文版

Imperfect C++中文版

威尔逊 / 荣耀、刘未鹏 / 人民邮电出版社 / 2006-1 / 75.0

汇集实用的C++编程解决方案,C++虽然是一门非凡的语言,但并不完美。Matthew Wilson使用C++十年有余,其间发现C++存在一些固有的限制,需要一些颇具技术性的工作进行弥补。本书不仅指出了C++的缺失,更为你编写健壮、灵活、高效、可维护的代码提供了实用的技术和工具。Wilson向你展示了如何克服C++的复杂性,穿越C++庞大的范式阵列。夺回对代码的控制权,从而获得更理想的结果。一起来看看 《Imperfect C++中文版》 这本书的介绍吧!

MD5 加密
MD5 加密

MD5 加密工具

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换