用一种更有条理的方法写Flutter代码——使用Flutter Hooks与函数式组件
今天在学习Flutter时了解到flutter_hooks和functional_widget两个第三方库,大为震撼。下面花两段稍微讲一下这两个库是啥,当然要深入了解还得是去看官方文档:
flutter_hooks把React中的Hook概念引入到了Flutter中,消除了Flutter的StatefulWidget和State类,所有状态和变量都改用类似React Hook的useXxx方式管理(可以说基本上把Flutter原本的语法翻新了个遍)。flutter_hooks的优势在于可以重用状态逻辑代码,关于flutter_hooks可以参考这篇文章
functional_widget可以通过一个@swidget注解将Flutter中函数式组件转化为一个类组件。它最大的益处可能就是类组件能够被const修饰,因而可以启动Flutter的const优化。而且函数式组件比类组件更加简洁、直观。这里我的想法是functional_widget可以用于写组件的样式代码。
经过一段时间的摸索,我研究出了一套这样的Flutter的代码,结合了flutter_hooks和functional_widget的优势(阅读前需要先了解flutter_hooks和functional_widget):
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:functional_widget_annotation/functional_widget_annotation.dart';
part 'hook_demo.g.dart';
//-----视图代码-----
class HookDemo extends HookWidget{
const HookDemo({super.key});
@override
Widget build(BuildContext context) {
final counter = Counter.use(0);
return Column(
children: [
const $Title(Text("A COUNTER DEMO",style: $TitleStyle,)),
SubTitle("Counter Value: ${counter.value}"),
$Line(ElevatedButton(onPressed: counter.inc, child: const Text("Add"))),
$Line(ElevatedButton(onPressed: counter.dec, child: const Text("Minus"))),
]
);
}
}
//-----方法代码-----
class Counter{
static use(initialValue){
return Counter()
.._count=useState(initialValue);
}
late final ValueNotifier<int> _count;
get value => _count.value;
inc(){
_count.value ++;
}
dec(){
_count.value --;
}
}
//-----样式代码-----
@swidget
Widget $line(e)=>Padding(
padding: const EdgeInsets.symmetric(vertical: 5),
child: e,
);
@swidget
Widget $title(e)=>Padding(
padding: const EdgeInsets.symmetric(vertical: 5),
child: Container(
color: Colors.amber,
width: 230,
child: Column(
children: [
e, Container(height: 2,color: Colors.grey)
],
),
)
);
@swidget
Widget subTitle(text)=>Text(text,style: const TextStyle(color: Colors.blue),);
const $TitleStyle = TextStyle(fontSize: 25,fontWeight: FontWeight.bold);
代码的执行结果:
没错,这依旧是一个计数器的demo!但是代码的书写形式却与一般的Flutter相去甚远。
这样写代码有什么优势呢?我们来看看这段代码的特点:
①有意识地对视图、方法和样式代码进行了分离
可以发现,这一段代码呈现的结构是这样的:
//-----视图代码-----
class 组件名 extends HookWidget{
@override
Widget build(BuildContext context) {
return 视图内容;
}
}
//-----方法代码-----
class 模块名{
模块中的方法、变量
}
//-----样式代码-----
@swidget
Widget $样式名(e)=>函数式组件
视图、方法和样式的代码被划分到三个部分(如果熟悉Vue的话,会发现这就是Vue的SFC的组织方式)。这样的效果是,可以减少视图代码中的组件嵌套。因为Flutter中的样式代码是用嵌套Widget的形式实现的,但这里我们把诸如Padding、ClipPath、GestureDetector这样的样式代码都放在了第三段部分,而把Row、Column、ListView这样的视图代码放在第一段部分,可以说是彻彻底底地减少了视图代码的嵌套问题。
②使用Flutter Hook,可以实现逻辑复用
我们熟悉(且讨厌的)的setState和StatefulWidget不见了,转而变成了下面两段代码:
//----视图代码----
Widget build(BuildContext context) {
final counter = Counter.use(0);
...
}
//-----方法代码-----
class Counter{
static use(initialValue){
return Counter()
.._count=useState(initialValue);
}
late final ValueNotifier<int> _count;
get value => _count.value;
inc(){
_count.value ++;
}
dec(){
_count.value --;
}
}
在Counter这个类中,我们定义了所有与计数器功能相关的代码,并且使用use函数来初始化。
在use函数中,用flutter_hooks的useState初始化了状态变量(useState前的两个点用到了Dart的级联符号语法)。
而在视图代码中,我们只需要用Counter.use就能初始化计数器的状态逻辑,并且可以通过counter.value访问、counter.inc改变它的状态。注意,这里因为使用了flutter_hooks,所以不再需要调用setState了!
这样做的一个好处是可以把每个功能都集中到类似于Counter这样的类中,例如,如果我们希望再添加一个Log功能,就可以再写一个Log类,并且在视图中调用Log.use(...)。另外一个好处是状态逻辑可以被复用,如Counter也可以用在其他的组件中,只需要使用Counter.use就可以启用一个计数器逻辑。
③保持了Flutter的const优化
Flutter能够对类组件进行const优化。这里因为使用了@swidget这个注解,可以将$title这样的函数组件(更准确来说,是一个样式函数,它接受一个子组件e,并返回包装后的组件,一般用$开头来命名样式函数),转化为一个类组件$Title(functional_widget会将转化后的类名首字母大写)。然后,在视图代码中调用$Title(....)时,由于它是一个类,所以可以被const修饰,从而可以启动Flutter的const优化。
总的来说,Flutter本身的语法虽然很古板,甚至还有令人生厌的“嵌套地狱”,但是结合flutter_hooks和functional_widget这样的第三方库,可以优化其代码结构,让代码更有条理。
相关文章
- Cocos2D绘制纹理的一般方法
- 大马过安全狗拿webshell方法
- SecureCRT乱码问题解决方法
- python解析模块(ConfigParser)使用方法
- SHELL 003 -- ss命令常用方法
- 数字图像处理 基于OpenCV的一种简单的阴影校正的方法
- Flutter进阶第5篇: 使用WebView组件flutter_inappbrowser加载远程web页面渲染新闻详情数据
- Flutter进阶第4篇: 实现简单的新闻系统渲染新闻详情数据以及用flutter_html解析html
- flutter 加.then方法
- flutter URL有方法获取其中参数
- flutter 插件版本冲突的解决方法
- flutter 界面的另一种写法,先写一部分再用Material,在方法体里面放方法体
- ML之FE:IV信息量(Information Value)指标(衡量变量的预测能力)的简介、计算逻辑、使用方法之详细攻略
- python类与类方法的实现
- 【Android 逆向】Android 逆向方法 ( 静态逆向解析 | 函数调用分析 | 动态运行跟踪 | 运行日志分析 | 文件格式解析 | 敏感信息分析 | 网络信息监控 | 环境伪装模拟 )
- 炒股的策略方法
- Win11因为文件包含病毒或潜在垃圾软件无法卸载解决方法
- Win11系统无法创建pin密码的解决方法教学
- C#里使用ExcelDataReader读取EXCEL文件的简单方法
- background-position 使用方法具体介绍
- java 静态方法和实例方法的区别
- Java8新特性之Stream--Stream方法
- 并发基础篇(六):线程Thread类的start()方法和run()方法