像 jQuery 一样通过函数开发和调用小程序组件

简介: 像 jQuery 一样通过函数开发和调用小程序组件
🙋🏻‍♀️ 编编拎重点:本文是蚂蚁集团前端工程师奇谈的分享,作者提出一种小程序开发方法,可以让你以 jQuery 函数式编程风格开发小程序,欢迎查阅。


前言

目前小程序开发中,React 技术栈是主流,大部分人都在使用“类 Class 组件”开发小程序,即通过声明一个对象,使用各种生命周期来开发一个组件,最典型的是支付宝 AppX 框架以及微信小程序,我们也叫原生小程序。当然,也有部分是使用“ Hooks ”开发组件的,比如 Remix 等。Class 组件和 Hooks 组件各有优缺点。Class 组件的问题在于组件之间复用状态逻辑很难复杂组件变得难以理解难以理解的 Class,这些是 React 官网的原话,相信有过编写 Class 经验的人都知道。Hooks 的问题在于上手门槛高了,你必须对 React 和 Hooks 有更深刻的理解,否则很容易写出 bug 。遥想当初我们使用 jQuery 一把梭哈的时候,是不是很简单?是不是很单纯?不用理解那么多的造出来的概念,回归到最原始的以解决问题为目标的编程。本文提出一种小程序开发方法,可以让你以 jQuery 函数式编程风格开发小程序。


先看 demo

用方代码:

上面是一个典型的交互组件:弹窗输入框组件

1. 我们通过 this.hook(componentName) 拿到输入框组件实例。

2. 输入框组件提供一个 show() 函数,用于显示弹窗。

3. 用户在输入框里面编辑、修改内容,然后点击完成按钮。

4. show() 函数同步返回输入框的值。对输入框组件来说,我们只关心它的返回值。

5. 最后我们把用户输入的值通过 setData 显示在页面上,再通过 close() 方法关闭弹窗。

可以看到,上面的代码调用一个输入框组件,就和 jQuery 组件一样,通过函数就能完成。那么我的 AXML 应该怎么写呢?很简单,AXML 只需要一行:

只需要在第10行声明一下组件的名称 componentName 就行了,然后你就可以通过 hook(componentName) 拿到这个组件的实例了。任何函数式组件都只需要一行就可以搞定。那么又会问了,这个 inputPopup 组件是怎么写的呢?很简单,小程序怎么写组件就怎么写,来看代码:

组件的代码有点多,没关系,我们来分析下:

这是一个标准的小程序写法,没有创造新的语法和DSL,大家应该很熟悉。我们先来看入口,组件提供的 showclose 方法就是在 install生命周期里面返回的。install 生命周期在小程序初始化时执行,整个小程序应用周期内只执行一次,它应该返回一个对象,这个对象就是组件实例的值,也就是说组件返回什么值,调用方拿到的就是什么值。我们的组件返回了 show 和 close 2个函数,所以我们可以通过 input.show 来调用它。那么当我调用 input.show 时发生了什么呢?很简单,它就是 JavaScript 的函数调用。可以看到 show 和 close 就是组件的2个属性,它和小程序的 methods完全一样,你可以在函数里面通过 this 访问实例,通过 setData 触发视图响应。现在你明白了吗?页面和组件的通信不再是 React 的 Props 了,也不再是 React Hooks 了,而是原生的 JavaScript 函数调用。这就是小程序函数式调用组件。


这意味着什么?

函数式调用组件是什么东西?它本质上是一种设计模式,就和 Class 组件以及 React Hooks 一样,你也可以理解为它是另一种组件间通信方案。正如 React Hooks 里面介绍的一样,请记住函数式调用组件是:

  • 完全可选的。 你无需重写任何已有代码就可以在一些组件中尝试函数式组件。
  • 100% 向后兼容的。 函数式组件不包含任何破坏性改动。它没有创造新的语法和DSL,它完全运行在原生小程序之上。
  • 现在可用。 函数式组件已经发布,并且已经在线上运行1年多了。

它和 Class 组件以及 React Hooks 有什么优点?

如果你认真的看了上面的demo,你就会发现它的优点。它在设计之初,就是为了解决 Class 和 React Hooks 的问题:Class组件写起来麻烦且很难维护。React Hooks 上手门槛高且更复杂。下面我们分析下函数式组件如何解决上面的问题:

先说和 Class 对比

Class 组件最大的问题在于各种生命周期,其中最令人头疼的是componentDidUpdate。它让复杂组件变得无法阅读和维护,试想一下,当你编写一个复杂交互的组件时,它接受 N 个 Props 可选项,然后在 componentDidUpdate里面一堆的比较代码,就为了找出哪个 Props 变更了。我曾经维护过一个 h5 数字键盘组件,当其中一个 Props 变更时,它就像一片雪花引起雪崩一样,你不知道下一个状态会是什么。componentDidUpdate另一个致命的问题是:新手经常会写出死循环的代码。

函数式组件如何解决?

既然componentDidUpdate 的设计模式让问题变得复杂,那我们就不用它,把它干掉。所以函数式组件里面没有这种循环的生命周期。它和组件之间的通信就是通过原生的 JavaScript 函数调用,使用函数入参来代替 Props。函数调用我们已经非常熟悉了,它的行为是明确的,它让我们的代码执行流程变得有章可循。函数入参带来的另一个好处是:它让我们的 data 保持干净。

试想一下你的组件有 10个 Props 来控制行为,你的 data 里面就必须有 10 个额外的字段,这本来是没必要的,因为它们仅仅是临时变量。

再说和 React Hooks 对比

React Hooks 干掉了 Class 和 生命周期,也干掉了 componentDidUpdate,它让组件完全由 JavaScript 函数编写,函数入参就是 Props,这看起来和我们刚刚说的函数式调用组件是一样的。但它在解决 Props 更新的问题上,又选择了重复执行的方式,也就是说,我们的 Hooks 组件又回到了无限循环执行的噩梦中。重复执行对 Props 来说是正确的,因为我们的组件永远应该渲染最新的 Props。但其它应该保持引用的变量却不能重复创建。 然后为了解决重复执行带来的变量无法保持引用的问题,又带来了 useStateuseCallback 等,就是这些东西让我们的 Hooks 组件变得以理解。你必须要理解 Hooks 的原理,否则很容易写出 bug 或者存在性能问题的组件。

函数式组件如何解决?

和 React Hooks 一样,我们选择用函数调用来代替 componentDidUpdate,用函数入参来代替 Props。但在如何更新 Props 上,函数式组件选择了使用额外的函数调用来解决重复调用的问题。为什么要这样设计呢?Class 的好处是拥有实例状态,它可以很方便的让我们保存和读取需要引用的变量,为了弥补componentDidUpdate 带来的问题,我们以明确的函数调用来替换由 Props diff 触发的调用。仅仅是一个微小的改动,函数式组件让 Class 和 Hooks 的优点结合在一起。你可能会说这是四不像,又有 Class 又有 Hooks 的思想在里面,那你这个到底是什么东西。它就是函数式调用组件。实际好不好用,还得在实践中证明。至少,它让我在开发复杂交互组件时,不必浪费时间在调试组件间通信问题,也不必浪费时间在如何管理 Props 以及 diff 上,我只要考虑哪些部分代码应该放在组件里。即使时隔一年,我再回过来看复杂交互的组件代码,我也能很快清晰的整理出它的执行流程。

再BB两句

我再啰嗦几句:函数式调用组件完全是在原生小程序之上构建的,它运行在运行时,而不是构建时,它没有破坏小程序现有规则,也不依赖任何框架,它可以和原生小程序共用。

最后BB两句

函数式组件灵感来源于真实业务中,当初是为了解决小程序中大量的复杂交互,很多交互都是带有 RPC 请求的,并且还涉及到缓存、并发、时序问题,这样增加了小程序开发难度,尤其是小程序中涉及到输入框的,相信深度研究过小程序输入框的都被它折磨过。这其中有大量的交互会复用在各个页面中,自然我们想把它作为一个组件复用,但写 Class 组件实在是让我们心力交瘁,一个是项目时间紧,基本倒排,另一个是复杂度和可维护性。所以我们就想,一个带有交互的组件,它的行为触发一定是明确的,就好像我们想要调用一个模块或者一个系统时,它提供一个 API,提供入参,然后我们调用它,它处理后返回结果给我们。这就是函数调用,UI 交互一定是因为某一个明确的事件触发,可以是一个点击事件,一个长按事件,一个明确的事件触发一个明确的函数调用,函数里面处理交互的结果。声明式的思想适合不带交互的UI组件,或者是交互结果明确能执行的组件,如果遇到交互结果可能会被回滚的情况,声明式组件如何表示声明被撤销的情况呢?

相关文章
|
2天前
|
传感器 小程序 搜索推荐
(源码)java开发的一套(智慧校园系统源码、电子班牌、原生小程序开发)多端展示:web端、saas端、家长端、教师端
通过电子班牌设备和智慧校园数据平台的统一管理,在电子班牌上,班牌展示、学生上课刷卡考勤、考勤状况汇总展示,课表展示,考场管理,请假管理,成绩查询,考试优秀标兵展示、校园通知展示,班级文化各片展示等多种化展示。
20 0
(源码)java开发的一套(智慧校园系统源码、电子班牌、原生小程序开发)多端展示:web端、saas端、家长端、教师端
|
8天前
|
小程序 JavaScript Java
基于SpringBoot+Vue+uniapp微信小程序的外卖小程序的研究与开发的详细设计和实现
基于SpringBoot+Vue+uniapp微信小程序的外卖小程序的研究与开发的详细设计和实现
12 0
|
9天前
|
小程序 JavaScript Java
基于SpringBoot+Vue+uniapp微信小程序的智慧旅游平台开发微信小程序的详细设计和实现
基于SpringBoot+Vue+uniapp微信小程序的智慧旅游平台开发微信小程序的详细设计和实现
27 8
|
9天前
|
JavaScript Java 测试技术
基于ssm+vue.js+uniapp小程序的二手交易平台设计与开发附带文章和源代码部署视频讲解等
基于ssm+vue.js+uniapp小程序的二手交易平台设计与开发附带文章和源代码部署视频讲解等
17 0
|
9天前
|
JavaScript Java 测试技术
基于ssm+vue.js+uniapp小程序的文化遗产的保护与旅游开发附带文章和源代码部署视频讲解等
基于ssm+vue.js+uniapp小程序的文化遗产的保护与旅游开发附带文章和源代码部署视频讲解等
12 1
|
13天前
|
JavaScript Java 测试技术
基于ssm+vue.js+uniapp小程序的校园二手交易平台的设计与开发附带文章和源代码设计说明文档ppt
基于ssm+vue.js+uniapp小程序的校园二手交易平台的设计与开发附带文章和源代码设计说明文档ppt
38 2
|
17天前
|
JavaScript Java 测试技术
基于微信小程序校园订餐的设计与开发+ssm+vue.js附带文章和源代码设计说明文档ppt
基于微信小程序校园订餐的设计与开发+ssm+vue.js附带文章和源代码设计说明文档ppt
25 1
|
1天前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp小程序的校园食堂订餐系统附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp小程序的校园食堂订餐系统附带文章源码部署视频讲解等
29 10
|
1天前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp小程序的校园失物招领网站附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp小程序的校园失物招领网站附带文章源码部署视频讲解等
21 9
|
1天前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp小程序的校园生活服务平台附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp小程序的校园生活服务平台附带文章源码部署视频讲解等
27 9