react hooks 如何自定义组件(react函数组件的封装)
前言
这里写一下如何封装可复用组件。首先技术栈 react hooks + prop-types + jsx封装纯函数组件。类组件和typeScript在这不做讨论,大家别白跑一趟。
接下来会说一下封装可复用组件的思路,比如一个新手应该怎么去封装,都需要注意哪些东西。
然后说一些复杂组件需要的功能,比如闭合标签内部dom怎么处理,其实就是插槽功能,比如数据监听,内部做一些业务逻辑。
想看原码的点这里,这是我GitHub上完整的 react hooks 项目, 点这里,看源码
目录
1、思路 及 封装的误区
2、 props 的类型检测、默认值
3、组件调用及数据互通
4、实现类似于vue插槽一样的功能 (children属性)
5、useState、useEffect等hooks讲解
6、总结
一、思路
无论是js还是C++等等,都要求 模块内高内聚、模块间低耦合。简单点说就是你改了一个模块,另一个模块稍作修改就行,不至于改动很大。根据这个编程思想,一个可复用组件的对外交互,就是决定他耦合度的关键。把组件比作香肠机,输入猪肉,输出香肠。输入就是props,输出就是界面效果 以及 给外部反馈的回调函数。关于输入props,我们对他有要求,就是类型检查和默认值。比如输入的得是猪肉不能是石头,默认做小香肠,而不是大香肠。回调函数也有要求,你得尽可能满足可以预知的逻辑,简单说就是你以后用这个组件的时候,需要某个数据,这个组件得支持,得有对应的回调能让你拿到你想要的的东西。
注意,这里说几个误区,也是很多人经常犯错的地方。
1、项目中可复用组件我认为有2种,并不是所有组件都按照一套标准去规范
第一种 全局可复用组件,这类组件类似于antd那种ui库,是提供给开发项目所有人使用的,频率高。这一类必须严格规范,不能乱搞。必须有props的类型检查,有需要的props得加默认值;组件只能接收props作为数据来源,通过回调函数反馈,严禁其他任何形式的输入输出改(其实回调函数也是props,只不过是函数类型的,为了功能上做区别,后续我都会这样称呼);必须对组件功能,props,内部的方法等添加注释。
第二种 是一些局部功能组件,这一类可能只在部分特定情况下会使用,不需要像第一种那种严格要求,比较灵活多变,尽可能以简单通俗易懂去编写他,比如接下来要描述的几种禁忌,这类组件并没有这些要求,只要代码精简、便于维护、易读。你想怎么写都行。
2、全局组件
避免使用redux一类的状态管理,能用props实现就别懒
避免使用ref获取组件数据,能用回调的都写上回调,ref可读性很差
保持纯净,自己开发的组件可以相互引用,但是尽可能避免对第三方、包括UI框架的使用。当然这也不是绝对,二次封装组件很常见,只是有条件的尽量自己开发。
二、 props 的类型检测、默认值
我们使用prop-types做props类型检查,得安装一下
npm i prop-types
看下面的代码,首先引入 prop-types ,然后创建我们的函数组件,这里有几点需要注意的,首先,先定义组件,然后在组件原型上绑定类型检查;其次因为是函数组件,所有用prop-types做类型检查的props,都必须在函数组件的形参中显式的声明,否则不好使。看代码也能理解毕竟绑定在原型上,初始化的时候不声明,就没办法绑定校验了。所以,我建议一种写法,所有props都做检查,都在形参中声明,能赋默认值的,都写上默认值,然后在形参的后面把注释都写明白了,这样代码一目了然,换个人也可以很容易接手你的代码。这里啰嗦一嘴,函数组件,本质就是个函数,所以默认值这些都是js函数形参赋默认值的写法。
额外啰嗦两句prop-types的用法,后面这个是他的用法说明: https://zh-hans.reactjs.org/docs/typechecking-with-proptypes.html
链接包括所有的类型、一个props声明多种类型,对象内部属性的类型校验,甚至是定义一个类型检查函数等用法。
三、组件调用及数据互通
处理好了props,我们处理回调,如图所示,是我写的一个简单的回调。这里一般不写默认值,但是要做非空判断,因为不是所有的属性,使用者都需要。每个全局组件都需要有份文档,不但描述逻辑功能,还有所有属性的的描述,像函数这类,需要有示例的,形参含义说明白。
四、实现类似于vue插槽一样的功能 (children属性)
封装组件经常会遇到需要 插槽 的情况,简单说就是你封装了一个闭合组件,内部的dom你想对他做一些处理,比如样式上的。这里说一下应该怎么做。看图,注意,如果有一个根标签,children就是个对象,如果多个并列标签的话,children就是数组,用法不一样,这里根据需求来,我这里用的是对象,也就是顶层只有一个标签,注意需要定义children的类型,是标签,还是一个数组的标签。图中代码类型定义是一个react标签,所以如果别人写了并列的div,就会报警告这样自然可以很好的约束使用者。
五、useState、useEffect等hooks讲解
最后写一点函数组件的使用心得。首先父组件变化 或者 函数组件内部变量变化,都会导致函数组件重新执行,如果你在return前面写个console,会发现执行了很多次,复杂的界面甚至能执行几十次,这点很操蛋,不过最终diff的时候react会做优化,合并很多变化,当然很多时候执行太多次,还是代码有问题的,需要你尽可能的优化下代码,提升性能。其次,函数组件只有hooks,没有生命周期,这和类组件差异很大,代码逻辑也改变很大,很多人刚一接触hooks和函数组件会感觉很懵逼,不知道该怎么写代码。关于这点,我不打算在这里讲太多,毕竟这是介绍封装组件的文章。react的文档属于心智模型,非常nice,大家应该都能看得明白,接下来我会写几个看文档不容易了解,实际撸代码又很重要的东西。
1、函数会不断执行,如果在函数内部声明变量或者常量会不断被初始化,所以要么用useState声明要么直接放到函数外,比如标记1、3 、4。否则,声明的变量就会是个定值。
2、useState声明的变量,默认值只会赋值一次,他只会触发一次,比如标记 2。
3、函数组件没生命周期,所有功能都集合到useEffect身上了,它 用于监听变量变化,可以监听useState的也可以监听我们那个标记1这种函数外的。他第二个参数传空数组,就只会在组件初始化的时候执行一次,可以在这初始化数据,发http请求,或者时间绑定等。他的触发机制实在dom渲染结束之后。比如标记 5,如果加return,卸载的时候也会执行return的逻辑,这其实就是他实现生命周期功能的用法之一。
4、useMemo 通过这个hooks可以优化组件的渲染次数,它根据指定变量变化控制函数是否执行
u
六、总结
关于react hooks封装可复用组件,暂时就想到了这么多,文章开头我贴了GitHub的项目地址,因为要说的东西比较多,没法一个例子就把所有东西清晰、条理的说明白,期间我截图了好几个组件的代码,大家看源码的话,直接看components文件夹。
vue3的setup参考了react hooks,从用法上说,vue的改变还能让人接受些,毕竟他只是将之前的属性换到了setup的原型上。react这波真的是大变样,类组件和函数组件真的就完全是2套代码了。
这里说一下我自己的感悟,这两个框架先是变得雍容华贵,功能很多,现在又返璞归真,追求灵活,贴近js。对我最大的体会就是以后的码代码变难了。升级之后vue和react上手难度都提升了很多,提高了对js基础的理解。有经验的程序员写出的代码,精简干练,部分地方,新手可能会看不懂。新手写出来的代码,有可能乱成一锅粥,其他人都看不懂。所以希望大家多写注释,好好撸代码,把这个编程的风气提高上来。
博主真的是遇到过很多垃圾代码,深受其苦,大多是大家都不想优化代码,这糊一块,那加一段,代码越来越乱,最后走向重构的结局。裱糊匠太难了