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

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

内容简介: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强大的扩展能力制作更多组件来满足不同业务对于框架的需求。


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

查看所有标签

猜你喜欢:

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

ANSI Common Lisp

ANSI Common Lisp

Paul Graham / Prentice Hall / 1995-11-12 / USD 116.40

For use as a core text supplement in any course covering common LISP such as Artificial Intelligence or Concepts of Programming Languages. Teaching students new and more powerful ways of thinking abo......一起来看看 《ANSI Common Lisp》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

html转js在线工具
html转js在线工具

html转js在线工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试