像 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组件,或者是交互结果明确能执行的组件,如果遇到交互结果可能会被回滚的情况,声明式组件如何表示声明被撤销的情况呢?

相关文章
|
11天前
|
小程序 前端开发 API
小程序全栈开发中的多端适配与响应式布局
【4月更文挑战第12天】本文探讨了小程序全栈开发中的多端适配与响应式布局。多端适配涉及平台和设备适应,确保统一用户体验;响应式布局利用媒体查询和弹性布局维持不同设备的布局一致性。实践中,开发者可借助跨平台框架实现多平台开发,运用响应式布局技术适应不同设备。同时,注意兼容性、性能优化和用户体验,以提升小程序质量和用户体验。通过这些方法,开发者能更好地掌握小程序全栈开发。
|
11天前
|
小程序 前端开发 API
微信小程序全栈开发中的异常处理与日志记录
【4月更文挑战第12天】本文探讨了微信小程序全栈开发中的异常处理和日志记录,强调其对确保应用稳定性和用户体验的重要性。异常处理涵盖前端(网络、页面跳转、用户输入、逻辑异常)和后端(数据库、API、业务逻辑)方面;日志记录则关注关键操作和异常情况的追踪。实践中,前端可利用try-catch处理异常,后端借助日志框架记录异常,同时采用集中式日志管理工具提升分析效率。开发者应注意安全性、性能和团队协作,以优化异常处理与日志记录流程。
|
11天前
|
小程序 安全 数据安全/隐私保护
微信小程序全栈开发中的身份认证与授权机制
【4月更文挑战第12天】本文探讨了微信小程序全栈开发中的身份认证与授权机制。身份认证包括手机号验证、微信登录和第三方登录,而授权机制涉及角色权限控制、ACL和OAuth 2.0。实践中,开发者可利用微信登录获取用户信息,集成第三方登录,以及实施角色和ACL进行权限控制。注意点包括安全性、用户体验和合规性,以保障小程序的安全运行和良好体验。通过这些方法,开发者能有效掌握小程序全栈开发技术。
|
11天前
|
小程序 前端开发 安全
小程序全栈开发中的跨域问题及其解决方案
【4月更文挑战第12天】本文探讨了小程序全栈开发中的跨域问题及其解决方案。跨域问题源于浏览器安全策略,主要体现在前后端分离、第三方服务集成和数据共享上。为解决此问题,开发者可采用CORS、JSONP、代理服务器、数据交换格式和域名策略等方法。实践中需注意安全性、兼容性和性能。通过掌握这些解决方案,开发者能更好地处理小程序的跨域问题,提升用户体验。
|
11天前
|
小程序 前端开发 JavaScript
微信小程序全栈开发中的PWA技术应用
【4月更文挑战第12天】本文探讨了微信小程序全栈开发中PWA技术的应用,PWA结合Web的开放性和原生应用的性能,提供离线访问、后台运行、桌面图标和原生体验。开发者可利用Service Worker实现离线访问,Worker处理后台运行,Web App Manifest添加桌面图标,CSS和JavaScript提升原生体验。实践中需注意兼容性、性能优化和用户体验。PWA技术能提升小程序的性能和用户体验,助力开发者打造优质小程序。
|
11天前
|
小程序 前端开发 API
小程序全栈开发中的RESTful API设计
【4月更文挑战第12天】本文探讨了小程序全栈开发中的RESTful API设计,旨在帮助开发者理解和掌握相关技术。RESTful API基于REST架构风格,利用HTTP协议进行数据交互,遵循URI、客户端-服务器架构、无状态通信、标准HTTP方法和资源表述等原则。在小程序开发中,通过资源建模、设计API接口、定义资源表述及实现接口,实现前后端高效分离,提升开发效率和代码质量。小程序前端利用微信API与后端交互,确保数据流通。掌握这些实践将优化小程序全栈开发。
|
11天前
|
SQL 安全 小程序
探索微信小程序全栈开发的安全性问题
【4月更文挑战第12天】本文探讨了微信小程序全栈开发中的安全性问题,包括数据安全、接口安全、隐私保护和代码安全。为解决这些问题,建议采取数据加密、使用HTTPS协议、身份认证与授权、输入验证、安全审计及漏洞扫描以及安全培训等措施。通过这些方法,开发者可提升小程序安全性,保护用户隐私和数据。
|
11天前
|
JavaScript 前端开发 小程序
微信小程序全栈开发之性能优化策略
【4月更文挑战第12天】本文探讨了微信小程序全栈开发的性能优化策略,包括前端的资源和渲染优化,如图片压缩、虚拟DOM、代码分割;后端的数据库和API优化,如索引创建、缓存使用、RESTful API设计;以及服务器的负载均衡和CDN加速。通过这些方法,开发者可提升小程序性能,优化用户体验,增强商业价值。
|
1月前
|
小程序 API
点餐小程序实战教程09-订单功能开发
点餐小程序实战教程09-订单功能开发
|
1月前
|
小程序 UED
人力资源小程序的设计与开发步骤
人力资源小程序的设计与开发步骤
20 1

热门文章

最新文章