阿里宣开源应用框架Flutter Fish Redux!
闲鱼宣布Fish Redux在GitHub开源。 Fish Redux 是一个基于 Redux 数据管理的编译型 Flutter 应用框架。它特别适合构建中型和大型复杂应用。其最显着的特点是函数式编程模型。可预测的状态管理、可插拔组件系统和最佳性能。下面我们将详细介绍Fish Redux的使用特点和流程。以下内容来自InfoQ对闲鱼Flutter团队的独家专访以及Fish Redux开源文档。
开源背景
闲鱼接入Flutter时,我们的实现方案是尝试最复杂的主链路来验证Flutter的完整性,而我们的细节整体业务比较复杂,主要体现在两个方面:
- 页面需要集中的状态管理,这意味着不同的页面组件共享一个数据源,并且数据源的更改必须传达给所有页面组件。
- 网站UI展现形式较多(如通用详情、闲鱼币详情、社区详情、拍卖详情等),工作量较大,因此UI组件需要尽可能复用,这意味着需要更好地实施这些组件。分割。
当我们尝试使用市场上现有的框架(Google提供的redux和block)时,我们发现没有一个框架能够同时解决中心化的状态管理和UI组件化,因为这两个问题有些矛盾(中心化vs分割规则) )。因此,我们希望框架能够解决我们的问题,redux for Fish 就诞生了。
Fish Redux 本身经历了多次迭代。你现在看到的版本经历了三个比较大的迭代,实际上也经过了团队内部大量的讨论和思考。
第一个版本基于社区的flutter_redux改造。核心是提供UI代码的组件化。当然,问题也很明显。对于复杂的细节和发布业务,往往存在大量的业务逻辑,而这些逻辑是不可能实现的。代码组件化。
第二个版本针对第一个版本的问题做了相当重大的修改,解决了UI代码和逻辑代码拆分的问题,但同时按照redux标准,违反了redux的原则。对于追求卓越的闲鱼团队来说,这是难以接受的;
因此,在第三版的重构过程中,我们确立了整体的架构原则和分层要求。一方面,我们根据reduxjs代码在flutter端进行了redux。实施,保持 redux 原则完整。另一方面,为了解决组件化的问题,我们在redux之上提供了组件封装,通过这个架构设计层创新地提供了分治业务代码的能力。
至此我们已经完成了fish redux的基本设计,但是在商业构建后的后续应用中我们发现了代码性能问题。为了解决这个问题,我们再次提供了相应的适配器选项来满足一长串的场景。下面的单元格有大问题。目前fish redux已经在线稳定运行三个多月了。未来,我们期待 Fish Redux 为社区带来更多信息。 ?
Redux
Redux是来自前端社区的数据管理框架。对于原生开发的同学来说可能有点陌生。我们来简单介绍一下。
Redux 是做什么的?
Redux是一个用于[可预测][集中][轻松调试][灵活]数据管理的框架。所有数据的添加、删除、修改、检查等操作均由Redux集中控制。
Redux 是如何设计和实现的?
Redux 是一个功能性数据管理框架。传统的OOP数据管理通常涉及定义一些bean,每个bean公开一些公共API来操作内部数据(重载模型)。
函数式方法代表了更高层次的抽象。数据的定义是一些结构体(贫血模型),操作数据的方法被统一到一个具有相同函数签名的Reducer中 (T, Action) => T 。
FP:Struct(贫血模型)+Reducer = OOP:Bean(重载模型)
同时,Redux 增加了 FP 中常用的中间件模式(AOP)和 Subscribe 机制,为框架和可扩展性。
贫血模型和过载模型请参见:
https://en.wikipedia.org/wiki/Plain_old_Java_object
Redux的缺点message的缺点Redux aonlyo不关心具体场景来使用吧。这是它的优点,同时也是它的缺点。
我们目前使用 Redux 时,面临两个具体问题:
- Redux 中心化与组件分而治之的矛盾;
- Redux的Reducer需要手动逐层组装,带来繁琐和简单。错误的性质。
Fish Redux 增强功能
Fish Redux 使用 Redux 来集中管理可观察量。不仅如此,针对传统Redux在使用层面的不足,我们在客户端flutter页面开发场景中通过更好、更高的抽象进行了改进。
组件需要定义数据(Struct)和Reducer。同时,组件之间存在父子依赖关系。通过这一层依赖,我们解决了【集中】和【分而治之】之间的冲突。同时,手动逐层组合由框架自动完成,大大简化了使用Redux的复杂度。我们得到了中心化和分治代码的预期效果。
遵循社区标准
上述State、Action、Reducer、Store和Middleware概念完全符合社区ReduxJS。我们完好无损地保留了 Redux 的所有优点。
如果想更详细地了解Redux,请参见:https://github.com/reduxjs/redux
组件
组件是本地显示和功能的封装。基于Redux原理,我们将函数分为修改数据的函数(Reducer)和不修改数据的函数(副作用)。
这样我们就得到了View、Effect、Reducer三个部分,称为三组件元素。它们负责组件的显示、非修改数据行为和数据修改行为。
这是面对现在和未来的分裂。目前从Redux的角度来看,就是数据管理等。 UI 表达式等内容是对 UI 自动化未来的展望。
UI表达即将进入程序员的黑盒时代。研发工程师会更加关注不修改数据的行为和不修改数据的行为。
组件划分并征服视图和数据。通过层层切片和挖掘,我们将复杂的页面和数据分解成独立的小模块。这将有利于团队内部合作的发展。
关于View
View只是一个函数签名:(T,Dispatch,ViewService) => Widget 主要包含三个方面的信息
- 显示完全是数据驱动的。
- 查看生成的事件/回调通过 Dispatch 广播“意图”,无需任何具体实现。
- 所需的组件依赖关系等。通过 ViewService 以标准方式调用。例如,符合View签名的典型函数。

关于效果
效果是非修改数据行为的标准定义。它是函数签名:(Context, Action) => Object。主要包含四个方面的信息
- 接收来自 View 的“意图”,还包含相应的生命周期回调,然后执行具体的执行。
- 它的处理可以是异步函数,并且过程中可以修改数据,所以我们不支持数据保留,而是通过上下文获取最新数据。
- 不更改数据。如果需要修改,则应将action发送到Reducer进行处理。
- 其返回值仅限于bool或Future,对应支持同步函数和协程的处理流程。
比如良好的协程支持:
关于Reducer
Reducer是一个完全符合Redux规范的函数签名:(T, Action) => T 该签名对应的一些reducers:
显式配置还用于完成小组件和大组件所依赖的适配器的注册。这种依赖关系的配置称为依赖关系。
于是就有了这个公式 Component = View + Effect(可选)+Reduce(可选)+ Dependency(可选)。
典型构建:
通过抽象组件,我们可以获得完整的分而治之、多维重用和更好的分离。
适配器
适配器还包括本地显示和功能。它是为高性能ListView场景而生,是组件实现上的改变。
旨在解决flutter-ListView场景下组件模型的三个问题:
1)在组件中插入“大单元格”无法受益于ListView代码的性能优化;
2)组件无法区分appear|disappear和init|dispose;
3)Effect生命周期与视图的连接在ListView场景下不符合直观预期。
简而言之,我们想要一个逻辑上的ScrollView和一个性能上的ListView,一个提供部分视图和功能封装的抽象。我们希望看到创建这样一个独立抽象层的实际效果。我们页面没有使用Component框架,而是使用Component+Adapter框架的基线对比。
- 减少是长期的,效果是中长期的,看法是短期的。
我们通过不断的测试进行比较,以Android电脑为例:
- 我们的详情页在使用FPS框架之前,基础值为52FPS;
- 使用该框架并仅使用组件抽象将 FPS 降至 40,陷入“Big-Cell”陷阱;
- 使用框架并使用适配器抽象,FPS 增加到 53,并返回到高于基线,这是一个小的改进。
目录
推荐的目录结构会是这样的
sample_page
-- action.dart
-- page.dart
-- view.dart
-- effect.dart
-- reducer.dart
-- state.dart
components
sample_component
-- action.dart
-- component.dart
-- view.dart
-- effect.dart
-- reducer.dart
-- state.dart
上层负责构建,下层负责执行。同时会提供插件模块,方便我们快速填写。
我们以闲鱼的详细场景作为组装的例子:
组件之间、组件到容器之间是完全独立的。
通讯机制
- 组件 |内部适配器通信
- 组件 |适配器之间的通信

简单描述:带优先处理段的广播,采用自先广播。
发出的 Action 将首先被处理,否则将被发送到其他组件和 Redux 进行处理。最后,我们通过简单直观的调度处理了组件内部和组件之间(父亲到孩子、儿子到父母、兄弟姐妹等)的所有通信需求。
恢复机制
数据恢复
- 部分数据修改自动触发上层数据逐层浅拷贝,对上层业务代码透明。
- 层层复制数据:
- 一方面是严格遵守Redux数据编辑。
- 另一方面,它也是严格显示驱动的数据跟踪。

显示刷新
向所有组件发送一个简单的通知,组件通过shouldUpdate函数确定是否需要刷新。
Fish Redux 的优势
集中式数据管理
通过 Redux 进行集中式可观察数据管理。我们将原样保留Redux的所有优点,同时Redux的合并将由框架代理自动完成,这大大简化了使用Redux的繁琐。
组件管理分而治之
组件分而治之视图和数据。通过层层切片和挖掘,我们将复杂的页面和数据分解成独立的小模块。这将有利于团队内部合作的发展。
显示、缩减、效果隔离
将组件拆分为三个相互独立的无状态函数。因为它是无状态函数,所以更容易编写、调试、测试和维护。同时,也带来了更多组合、复用、创新的可能性。
构建声明性配置
使用免费的声明性配置构建来完成组件和适配器。包括它的view、reducer、effect和依赖的children。
良好的可扩展性
核心框架保持主攻三层,不做主干以外的事情,同时保持向更高层的灵活扩展。
- 框架甚至没有一行打印代码,但我们可以通过标准中间件跟踪数据流和组件的变化。
- 除了框架的基本三层之外,还可以通过dart语言函数为组件或适配器添加mixins,灵活提高定制化以及在上层使用的可能性。
- 框架与其他中间件打通,如自动曝光、高可用等。中间件和框架是透明的,上层可以自由组装。
小、简单、完整
- 非常小,仅包含1000多行代码;
- 使用起来很方便,完成几个小功能,组装完成就可以出发了;
- 就完成了。
关于未来
开源后,闲鱼计划通过以下方式维护Fish Redux:
- 通过后续一系列的对外宣传,吸引更多开发者加入或使用。目前Flutter生态中的应用框架仍然是空的,有机会成为事实上的标准;
- 与闲鱼Flutter系列移动中间件矩阵合作开源;
- 还提供了一系列用于调试的配套开发工具,提高Flutter上层开发的效率和体验。
Fish Redux 已在阿里巴巴闲鱼技术团队的多个场景中深度应用。最后,Talk 很便宜,给我看看代码,我们今天在 GitHub 上正式开源了。如需了解更多信息,请前往 GitHub 了解更多信息。
GitHub地址:https://github.com/alibaba/fish-redux
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。