在2018年底,谷歌在开源社区的帮助下,发布了跨平台移动开发框架Flutter的第一个稳定版本,为移动开发者带来了一份伟大的礼物。
但是,在开发比单页Hello Worlds稍大的大型应用程序时,开发人员可能会遇到不确定性。 如何编写应用程序? 该框架还很年轻,使用开源仍然没有足够的好例子,在此基础上,有可能了解使用各种模式的利弊,了解在这种特殊情况下应该使用什么以及不应该使用什么。
Flutter与React和React Native有一定程度的相似性,从而避免了这种情况,这意味着您可以从后者的一些编程经验中学到东西。 也许正因为如此,诸如Flutter Flux , Flutter Hooks , MobX之类的库以及几种Redux实现立即出现了。 长期以来,最受欢迎的版本是Brian Egan,名为Flutter Redux 。
但是,几个月前, Fish Redux库以阿里巴巴的名义发布了第一次提交。 在短时间内,该图书馆获得了极大的欢迎,就布赖恩星数而言,已经在第一天就实现了,而在第二天,它就比它快了两倍。
尽管Fish颇受欢迎,但它在文档方面存在问题,其中大部分通过一些简短示例对现有类进行了描述。 更糟的是,某些文档仅提供中文。 还有一个困难:几乎没有英语问题,因此依靠其他开发人员的经验非常困难,这非常关键,因为只有第一个预览版本才发布。
那么,Fish'a版本的Brian的显着区别是什么? Flutter Redux是一个状态管理框架。 Fish是一个以Redux为中心的应用程序框架,它是状态管理的基础。 即 Fish解决了更多任务,并且不仅限于state management
。
Fish Redux的主要功能之一是通过直接表达它们之间的关系将多个化简器组合成较大的化简器,而常规的Redux根本不提供这样的机会,从而迫使开发人员自行实现所有功能。 但是,让我们稍后再讨论这个减速器以及Fish Redux本身。
组件中Reducer,Effect和View之间的关系

Fish Redux中所有组件的基础都是组件。 这是一个由三部分组成的对象:效果,还原器和视图。 值得注意的是,只有View,即 Effect和Reducer是可选的;没有它们,组件也可以工作。 该组件还具有当前状态。
州
例如,以一个答题器。 假设他的状态只有一个字段-计数,这将表示最佳点击次数。
class ClickerState implements Cloneable<ClickerState> { int count = 0; @override ClickerState clone() { return ClickerState() ..count = count; } }
国家必须是一成不变的。 通过实现Cloneable接口,可以轻松维护状态抗扰性。 将来,当您需要创建新状态时,只需使用clone()
方法。
减速器
减速器的本质是通过返回新状态来响应某些动作。 减速器不应产生任何副作用。
我们将编写一个简单的reducer,当接收到相应的Action时,counter会增加一个数字(大约低一点)。
ClickerState clickerReducer(ClickerState state, Action action) {
另外,该减速器可以用以下形式编写:
Reducer<ClickerState> buildClickerReducer() { asReducer({ Actions.increase: (state, action) => state.clone() ..count = state.count + action.payload,
动作片
动作-FishRedux库中的一个类,包含两个字段:
Object type
-操作类型,通常是一个枚举对象
dynamic payload
-动作参数,可选。
一个例子:
enum Actions { increase }
检视
逻辑已准备就绪,将保留显示结果。 View是一个将当前状态,调度,ViewService并返回Widget作为参数的函数。
需要发送功能来发送动作:一个动作,我们之前已经描述了它的创建。
ViewService包含当前的BuildContext(来自标准flutter库),并提供用于创建依赖项的方法,但稍后会涉及它们。
一个例子:
Widget clickerView(ClickerState state, Dispatch dispatch, ViewService viewService) { return RaisedButton( child: Text(state.count.toString()), onPressed: () => dispatch(ActionsCreate.increase(1))
组成部分
我们将从所有这些组装组件:
class ClickerComponent extends Component<ClickerState> { ClickerComponent() : super( reducer: clickerReducer, view: clickerView, ); }
如您所见,在我们的示例中未使用effect,因为 没必要。 效果是必须执行所有副作用的功能。 但是,让我们提出一个案例,其中没有效果就离不开它。 例如,这可能是我们从random.org服务获得的随机数增加了。
效果实施例 import 'package:http/http.dart' as http;
页数
Component的扩展名为Page <T,P>。 该页面包括两个附加字段:
T initState(P params)
-返回初始状态的函数。 创建页面时将被调用。
List<Middleware<T>> middleware
- List<Middleware<T>> middleware
的列表-将在reducer之前调用的函数。
还有一种方法:
Widget buildPage(P params)
-将页面收集到一个有效的小部件中。
让我们创建应用程序的主页:
class MainPage extends Page<void, void> { MainPage(): super( initState: (dynamic param) {}, view: (state, dispatch, viewService) => Container(), ); }
页面扩展了一个组件,这意味着它可以包含减速器,效果以及常规组件所具有的所有其他内容。
在该示例中,创建了一个空白页面,该页面既没有状态,也没有缩小器或效果。 我们稍后将解决此问题。
所有这一切都与Brian Egan的Flutter Redux以及Redux的其他实现形式稍有不同。 让我们继续新库的主要功能-依赖关系。
依存关系
Fish Redux要求您明确定义组件之间的依赖关系。 如果要在组件中使用子组件,则不仅需要编写这两个组件,还需要创建一个负责将一种状态转换为另一种状态的连接器。 假设我们要在MainPage页面中嵌入ClickerComponent。
首先,您需要将状态添加到我们的页面:
class MainState implements Cloneable<MainState> { ClickerState clicker; @override MainState clone() { return MainState() ..clicker = clicker; } static MainState initState(dynamic params) { return MainState() ..clicker = ClickerState(); } }
现在我们可以编写连接器:
class ClickerConnector extends ConnOp<MainState, ClickerState> { @override ClickerState get(MainState state) => state.clicker;
仅此而已。 一切准备就绪,可以添加我们的组件:
class MainPage extends Page<MainState, void> { MainPage(): super( initState: MainState.initState, dependencies: Dependencies( slots: { 'clicker': ClickerComponent().asDependent(ClickerConnector()),
因此,现在您可以通过将以下代码添加到main.dart
来构建一个完整的工作应用程序:
void main() => runApp(MyApp()); class MyApp extends StatefulWidget { @override _MyAppState createState() => _MyAppState(); } class _MyAppState extends State<MyApp> { @override Widget build(BuildContext context) => MaterialApp(home: MainPage().buildPage(null)); }
所有文件分隔的代码均可在此处获得 。 在Flutter上拥有良好的开发经验。