fish_redux是闲鱼技术团队打造的flutter应用开发框架,旨在解决页面内组件间的高内聚、低耦合问题。开源地址:https://github.com/alibaba/fish-redux前端
redux对于前端的同窗来讲是一个比较熟悉的框架了,fish_redux借鉴了redux单项数据流思
想。在flutter上说到redux,你们可能第一反应会类比到react上的react_redux。在react_redux中有个重要的概念——connect,react
connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])git
简单得说,connect容许使用者从Redux store中获取数据并绑定到组件的props上,能够dispatch一个action去修改数据。github
那么fish_redux中的connector是作什么的呢?为何说connector解决了组件内聚的问题?咱们应该如何理解它的设计呢?redux
尽管都起到了链接的做用,但fish_redux与react_redux在抽象层面有很大的不一样。框架
fish_redux自己是一个flutter上的应用框架,创建了本身的component体系,用来解决组件内的高内聚和组件间的低耦合。从connector角度来讲,如何解决内聚问题,是设计中的重要考量。ide
fish_redux本身制造了Component
树,Component
聚合了state和dispatch,每个子Component
的state经过connector
从父Component
的state中筛选。如图所示:函数
能够看到,fish_redux的connector的主要做用把父子Component
关联起来,最重要的操做是filter。state从上之下是一个严谨的树形结构,它的结构复用了Component
的树形结构。相似一个漏斗形的数据管道,管理数据的分拆与组装。它表达了如何组装一个Component
。源码分析
而对于react_redux来讲,它主要的做用在于把react框架和redux绑定起来,重点在于如何让React component具备Redux的功能。优化
从图中能够看到,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
单元连接到一个更大的
Component
或Adapter
上。这与咱们以前的描述相符合。
知道了connector
的基本做用,咱们来看一下它到底连接了哪些东西以及如何连接。
先来看一下ReportConnector
类的定义:
class ReportConnector extends ConnOp<PageState, ReportState>
ReportConnector
继承了ConnOp
类,全部connector
的操做包括+操做,都来自于ConnOp
类。
set/get
既然是数据管道,就会有获取和放置
set
函数的入参很好得表达了T
和P
的意思,即把一个P
类型的subState
合并到T
类型的
state
中。
再回头看get
函数,就很好理解了,get
函数表达的就是如何从T
类型的state
中获取P
类型
的subState
供Dependent
使用。
operator +
+
操做符的重载是咱们最初看到connector做用的地方,也是connector发挥做用的入口。
Logic
是Component
和Adapter
的父类,它表示页面组装元素的逻辑层,里面包含了
reducer
/effect
/higherEffect
等与逻辑相关的元素以及它的组装过程。
operator+
调用了createDependent
函数,接着会调用到_Dependent
类的构造函数,这里将
logic
和connector
放入_Dependent
内部,在后面fish_redux对Component
组装的过程当中,connector会随着外部对_Dependent
中函数的调用发挥做用。
铺垫了这么多,是该connector正式发挥做用的时候了。
get
咱们以Component
为例,会调用到_Dependent
的buildComponent
函数:
Widget buildComponent(MixedStore<Object> store, Get<T> getter) { final AbstractComponent<P> component = logic; return component.buildComponent(store, () => connector.get(getter())); }
这里的logic
实际就是一个Component
对象,在调用Component
的buildComponent
函数的
时候,使用get
函数从一个大的父state中获取到当前Component
须要的数据集。接下去,这个变换后的子state将被用在例如ViewBuilder
或Redcuer
函数中。
这是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> { @override ReportState 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; } @override void set(PageState state, ReportState subState) {} }
很明显的,在get
函数中,ReportState
从PageState
中得到了total/done字段。
闲鱼客户端的详情页彻底使用了fish_redux进行了重构,经过高内聚的Component+connector
形式,使得Component
能够被大量复用,很好得支持了5中类型的详情页。将来咱们会基于fish_redux强大的扩展能力制做更多组件来知足不一样业务对于框架的需求。
原文连接 本文为云栖社区原创内容,未经容许不得转载。