弄懂自定义 Hooks 不难,改变开发认知有点不习惯【玩转React】
前言
我之前总结逻辑重用的时候,就一直在思考一个问题。
对于逻辑复用,render props 和 高阶组件都可以实现,同样官方说 Hooks 也可以实现,且还是在不增加额外的组件的情况下。
但是我在项目代码中,没有找到自定义 Hooks 的身影,自己也很少写。所以是为什么呢?
遇到问题表示查漏补缺的机会来了。
遇到技术点先问几个为什么
偶尔我会先问自己几个为什么,然后去寻找答案。带着明确的目标,不容易漏掉重要的讯息。
- 什么是自定义 Hooks?很难实现吗?
- 自定义 Hooks 和普通函数有什么区别?
- 如何创建一个自定义 Hook?
- 为什么需要自定义 Hooks?哪些场景会用到?
- 为什么我好像平时用不到?
自定义 Hooks 很难吗?
自定义 hooks可以看做是 React Hooks 的之外的自由延伸。本质上还是 JavaScript 函数。主要用途是实现逻辑重用。
React Hooks、函数、逻辑重用,根据这些关键字观察,实现自定义 Hooks 应该不是很难。
自定义 Hooks 和普通函数有什么区别?
看了关于自定义 Hooks 的介绍,我冒出来了第二个小问号:
这跟普通的逻辑复用函数有什么区别呢?
于是,我认真阅读了React的官方文档,发现主要有两点区分:
- 名字应该始终以 use 开头。
- 在自定义 Hook 中调用其他 Hook。
如何创建一个自定义 Hook?
因为Hook 本质是 JavaScript 函数,所以创建自定义 Hook其实就是声明一个名字以 use 开头的函数。
useDateRange
这个自定义 Hook 的过程算是意外惊喜,我在看完官方的例子之后,一直在想我实际开发中有哪些部分可以通过自定义 Hook实现逻辑的重用。
然后意外发现了项目中存在的可优化空间,后续会陆续产出优化的经验。
这里我先以项目中常出现的日期选择器为例,演示一下创建自定义 Hook 的全过程。
自定义 Hook 介绍
当前的需求如下:
- 日期选择器,需要设置可选日期范围,超出1天~10天的范围不可选择。
- 选择某个日期之后,需要计算跟当天日期相差的天数,并回显到页面上。
注:日期选择器使用的 antd 提供的组件,所有的参数均可以在官网查看。
UI 效果
可选日期效果
相差天数回显
可复用逻辑提取
可复用的逻辑主要包括三个部分:日期选择器的可选限制、时间发生变化的回调函数、相差天数变量。
日期选择器的可选限制
moment.js 的 add 方法可以计算指定时间之后(或之前)的某个时间。结合 startOf 方法和 endOf 方法使用,可以确定可选范围的起始日期。
时间发生变化的回调函数
当选定日期的时候,回调函数会返回选中的日期。
相差天数
通过时间回调函数拿到当前选择的日期,使用 moment.js 的 diff 方法,与今天的日期做比较。diff 方法的第二个参数决定差值的度量单位,day表示天数。
/**
* @description 时间选择器的限制和相差天数
*/
import React, { useState, useCallback, useMemo } from 'react';
import moment from 'moment';
const useDateRange = () => {
// 相差天数
let [dayDiff, setDayDiff] = useState(0);
/**
* 可选时间范围 1~10
*/
const disabledDate = useCallback(current => {
const startTimer = moment()
.add(+1, 'days')
.startOf('day');
const endTimer = moment()
.add(+10, 'days')
.endOf('day');
return current && (current < startTimer || current > endTimer);
}, []);
/**
* 时间选择器选择操作 获取相差天数
*/
const dateChange = useCallback(dates => {
let nowDate = new Date();
let startData = moment(nowDate).format('YYYY-MM-DD');
let endData = moment(dates).format('YYYY-MM-DD');
dayDiff = moment(endData).diff(moment(startData), 'day');
setDayDiff(dayDiff);
}, []);
return { dayDiff, disabledDate, dateChange };
};
export default useDateRange;
使用 useDateRange
引入自定义的 useDateRange 这个 Hook,就可以拿到传入的参数了。
/**
* @description 日期选择页
*/
import React from 'react';
import { DatePicker } from 'antd';
import useDateRange from './hooks/useDateRange';
const ChangeDatePage = () => {
// 使用自定义 Hook
const { disabledDate, dateChange, dayDiff } = useDateRange();
return (
<div>
<DatePicker disabledDate={disabledDate} onChange={dateChange} />
<div className="mt20">选择的日期与今天相差: {dayDiff} 天</div>
</div>
);
};
export default ChangeDatePage;
自定义 Hooks 的优势和使用场景
等了解了它的优势,基本也就能联想到有哪些使用场景。
优势
自定义 Hooks 主要有两点优势:
- 逻辑复用
- 复杂代码分离
使用场景
通过对自定义 Hooks 了解和使用,可以归纳的使用场景主要包括三个大类:
封装可复用的逻辑、监听数据的状态、拆分复杂的逻辑
基于这三类场景,可应用的地方应该不少。未来一段时间,我准备改造一下我们的项目代码,这下事情开始有趣了。
为什么我好像平时用不到?
为何纠结用不到这件事?
先简单说一下最近为什么一直纠结用不到这件事。因为身处「业务驱动技术」的技术科技公司,业务迭代是很迅速的,想在快节奏的开发中,整个前端团队保持一个较高水平的开发水平,不是很容易。
想在逻辑复用上下一些功夫,提升开发效率,团队成员可以腾出一些时间进行技术升级。
开发认知
自定义 Hooks 和普通函数的界限是可变的,加上平时开发的命名不太习惯用 use 开头。
所以用到的少,并不是因为自定义 Hooks 的开发难度或者开发者技术水平,而是改变这个开发认知有点不习惯。
但是个人认为改变是有帮助的。
- 已知自定义 Hooks 主要用途是进行逻辑复用,那么从 use 开头的函数名,使用者不难联想到该函数方法是不是封装了某个公共的逻辑。
- 其实除了逻辑复用,复杂逻辑的拆分,也可以考虑用自定义 Hooks 实现。
今日总结
今天除了清楚自定义 Hooks的相关知识点、如何创建以及使用场景。还帮助我衍生了新的开发思路,让我对原以为无法进行逻辑复用的功能,有了新的想法。
后面如果有了更好的开发思路,会持续输出文章分享出来。
彩蛋
今天的彩蛋,讲个之前困扰过我问题以及后来我总结出来的经验。
现阶段一直在写业务代码,感觉技术上没有得到什么提升?
我之前也被这个问题困扰过。后来,我从身边很多优秀的思维中,总结了一些经验,也就不再纠结这个问题。
误区在哪?
技术和业务的关系,不是对立面,而是相辅相成、相得益彰的。尤其现在大多数是业务驱动型公司。已知「技术可推动业务的发展」,同样的业务日趋繁复,倒逼技术的更迭。
日复一日重复的功能?
遇到这个困惑时,不排除一种可能,受思维定式的影响,重复之前的实现方式。
但是功能本身未必不能用更好的方式去实现。
举个例子,搜索项常见于表格页面,因为每个页面的搜索项都不太一样,很长一段时间,都被散落在各个页面中。其实搜索项的类型基本就那几种,于是有同事封装了一个公共组件,只需要传入包含搜索项基础信息的配置数组变量即可。
以前散落在每个页面的搜索项,如果再加上事件的处理,冗余代码量会更多。
<div>
<label>城市:</label>
<Input placeholder='请输入城市' />
</div>
<div>
<label>分类:</label>
<Select placeholder='请选择'>
<Select.Option key='1'>分类1</Select.Option>
<Select.Option key='2'>分类2</Select.Option>
</Select>
</div>
后来封装成公共组件之后,代码简洁了很多,且大部分逻辑处理在组件中,使用时开发者并不用关心这些。
const fields = [
{
label: '城市',
fieldtype: 'input',
},
{
label: '分类',
fieldtype: 'select',
option: [
{
key: 1,
value: '分类1'
},
{
key: 2,
value: '分类2'
},
]
},
]
<Search fields={fields} />
工作中找不到项目练手?
我把日常的经验总结为:主动出击和没有条件创造条件。
- 如果有一定的能力,可以申请功能立项或者参与一些工程化建设项目。自己主动把握机会。
- 追随开拓者,自己创造条件。从模仿优秀的开源的项目到开发属于自己独立思维的项目过度,也是一个不错的选择。
总结时刻
三个问题和三个解答,解铃还须系铃人,心结还需自己解。
作者简介:
非职业「传道授业解惑」的开发者叶一一。
「趣学前端」、「CSS畅想」系列作者,华夏美食、国漫、古风重度爱好者,刑侦、无限流小说初级玩家。如果看完文章有所收获,欢迎点赞👍 | 收藏⭐️ | 留言📝。
- 点赞
- 收藏
- 关注作者
评论(0)