弄懂自定义 Hooks 不难,改变开发认知有点不习惯
前言
我之前总结逻辑重用的时候,就一直在思考一个问题。
对于逻辑复用,render props 和 高阶组件都可以实现,同样官方说 Hooks 也可以实现,且还是在不增加额外的组件的情况下。
但是我在项目代码中,没有找到自定义 Hooks 的身影,自己也很少写。所以是为什么呢?
遇到问题表示查漏补缺的机会来了。
遇到技术点先问几个为什么
偶尔我会先问自己几个为什么,然后去寻找答案。带着明确的目标,不容易漏掉重要的讯息。
1.什么是自定义 Hooks?很难实现吗?
2.自定义 Hooks 和普通函数有什么区别?
3.如何创建一个自定义 Hook?
4.为什么需要自定义 Hooks?哪些场景会用到?
5.为什么我好像平时用不到?
自定义 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 = () => {// 使用自定义 Hookconst { 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} />
工作中找不到项目练手?
我把日常的经验总结为:主动出击和没有条件创造条件。
- 如果有一定的能力,可以申请功能立项或者参与一些工程化建设项目。自己主动把握机会。
- 追随开拓者,自己创造条件。从模仿优秀的开源的项目到开发属于自己独立思维的项目过度,也是一个不错的选择。
总结时刻
三个问题和三个解答,解铃还须系铃人,心结还需自己解。
最后
整理了一套《前端大厂面试宝典》,包含了HTML、CSS、JavaScript、HTTP、TCP协议、浏览器、VUE、React、数据结构和算法,一共201道面试题,并对每个问题作出了回答和解析。
有需要的小伙伴,可以点击文末卡片领取这份文档,无偿分享
部分文档展示:
文章篇幅有限,后面的内容就不一一展示了
有需要的小伙伴,可以点下方卡片免费领取
相关文章:
弄懂自定义 Hooks 不难,改变开发认知有点不习惯
前言 我之前总结逻辑重用的时候,就一直在思考一个问题。 对于逻辑复用,render props 和 高阶组件都可以实现,同样官方说 Hooks 也可以实现,且还是在不增加额外的组件的情况下。 但是我在项目代码中,没有找到自定义 …...
Java面向对象基础
文章目录面向对象类注意事项内存机制构造器this关键字封装javabean格式成员变量和局部变量区别static静态关键字使用成员方法使用场景内存机制注意事项static应用:工具类static应用:代码块静态代码块实例代码块(用的比较少)static…...
基于python下selenium库实现交互式图片保存操作(批量保存浏览器中的图片)
Selenium是最广泛使用的开源Web UI(用户界面)自动化测试套件之一,可以通过编程与浏览量的交互式操作对网页进行自动化控制。基于这种操作进行数据保存操作,尤其是在图像数据的批量保存上占据优势。本博文基于selenium 与jupyterla…...
一:Datart的下载、本地运行
前言:本文只是个人在使用datart的一个记录,仅供参考。如果有不一样的地方,欢迎评论或私信进行交流。datart 是新一代数据可视化开放平台,支持各类企业数据可视化场景需求,如创建和使用报表、仪表板和大屏,进…...
Docker-compose
一.Docker-compose概述Docker-Compose项目是Docker官方的开源项目,负责实现对Docker容器集群的快速编排。Docker-Compose将所管理的容器分为三层,分别是 工程(project),服务(service)以及容器&a…...
经典文献阅读之--PLC-LiSLAM(面,线圆柱SLAM)
0. 简介 对于激光SLAM来说,现在越来越多的算法不仅仅局限于点线等简答特征的场景了,文章《PLC-LiSLAM: LiDAR SLAM With Planes, Lines,and Cylinders》说到,平面、线段与圆柱体广泛存在于人造环境中。为此作者提出了一个使用这些landmark的…...
计算组合数Cnk即从n个不同数中选出k个不同数共有多少种方法math.comb(n,k)
【小白从小学Python、C、Java】 【计算机等级考试500强双证书】 【Python-数据分析】 计算组合数Cnk 即从n个不同数中选出k个不同数共有多少种方法 math.comb(n,k) 以下python代码输出结果是? import math print("【执行】print(math.comb(3,1))") print(math.comb(…...
工厂设计模式
基本概念:为创建对象提供过渡接口,以便将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的。分为三类:简单工厂模式Simple Factory:不利于产生系列产品;工厂方法模式Factory Method:又称为…...
IO多路转接 —— poll和epoll
文章目录1. poll1.1 poll的函数接口1.2 poll的简单测试程序1.3 poll的优缺点分析2. epoll2.1 epoll的函数接口2.2 epoll的工作原理2.3 epoll的工作模式(LT,ET)2.4 epoll的简易服务器实现(默认是LT工作模式)前言: 接上文讲述的select,它有缺点,…...
计算机网络整理-问答
1. 程序工作的时候网络各层的状态 如下图所示: 1. TCP 在进行三次握手的时候,IP 层和 MAC 层对应都有什么操作呢? TCP 三次握手是通过在传输层建立连接的一个过程,在这个过程中,TCP 和 IP 层、MAC 层都起到了重要的…...
JS 实现抛物线动画案例
相信大家都有浏览过,很多购物网站购物车的添加商品动画,今天,我们就手写一个简单的抛物线动画,先上案例: 一、绘制页面 我们这里简单实现,一个按钮,一个购物车图标,样式这里直接跳过…...
CSGO搬砖项目,23年最适合小白的项目!
大家好,我是阿阳 不懂的小伙伴,咱继续听我娓娓道来 steam搬砖主要涉及的是csgo游戏平台装备的一个搬运,比较很好理解,主要就是道具的搬运工,简单来讲就是,从国外steam游戏平台购买装备,再挂到…...
谈谈会话管理
客户端和服务器之间进行数据传输遵循的是HTTP协议, 此协议属于无状态协议(一次请求对应一次响应, 响应完之后断开连接), 服务器是无法跟踪客户端的请求, 通过cookie技术可以给客户端添加一个标识, 客户端之后发出的每次请求都会带着这个标识从而让服务器识别此客户端, 但由于co…...
Linux查看JVM FULL GC频率
查看系统的full gc频率,可以使用jstack命令一、采用top命令定位进程登录服务器,执行top命令,查看CPU占用情况,找到进程的pid二、使用jstack命令统计垃圾回收jstat -gc pid 5000即会每5秒一次显示进程号为pid的java进程的GC情况以上…...
java世界String的那些事
String的创建机理: 由于String在Java世界中使用过于频繁,Java为了避免在一个系统中产生大量的String对象,引入了字符串常量池。其运行机制是:创建一个字符串时,首先检查池中是否有值相同的字符串对象,如果…...
【图像配准】多图配准/不同特征提取算法/匹配器比较测试
前言 本文首先完成之前专栏前置博文未完成的多图配准拼接任务,其次对不同特征提取器/匹配器效率进行进一步实验探究。 各类算法原理简述 看到有博文[1]指出,在速度方面SIFT<SURF<BRISK<FREAK<ORB,在对有较大模糊的图像配准时&…...
2023金三银四季跳槽季,啃完这软件测试面试题,跳槽不就稳稳的了
前言 2023年也到来了,接近我们所说的“金三银四”也正在执行了,时间晃眼就过去了,有的人为了2023跳槽早早做足了准备,有的人在临阵磨刀,想必屏幕前的你也想在2023年涨薪吧,那么问题来了,怎么才…...
【C++详解】——vector类
📖 前言:本期介绍vector类。 目录🕒 1. vector的介绍🕒 2. vector的使用🕘 2.1 定义🕘 2.2 iterator🕘 2.3 空间增长🕘 2.4 增删查改🕒 2. vector的模拟实现🕘…...
uniapp 离线本地打包
uniapp打包教程地址 https://nativesupport.dcloud.net.cn/AppDocs/usesdk/android.html点击查看 需要的环境: java (1.8)离线SDK(上面的连接下载即可)Android Studio(同上) 配置环境变量 依次点击“计算机”-“属性”&#…...
初识马尔科夫模型(Markov Model)
初识马尔科夫模型(Markov Model)一、概念二、性质三、学习步骤一、概念 马尔科夫模型(Markov Model)是一种概率模型,用于描述随机系统中随时间变化的概率分布。马尔科夫模型基于马尔科夫假设,即当前状态只…...
CentOS7 ifconfig(或 ip addr)命令不显示IP地址
问题(因为当时没有存图 所以这个图上是网上找的 )解决办法第一:可能是本地服务没有开启,检查本地服务。如图所示,检查这两个服务是否开启。注:如何快速找到服务 可以把光标放在其中一个上面 然后按下VM就可…...
2023/2/10总结
拓扑排序 拓扑排序是在一个有向无环图(DAG)所有顶点的线性排序。 拓扑排序核心思想非常简单,就是先找一个入度为0的顶点输出,再从图中删除该顶点和以它为起点的有向边。继续上面的操作知道所有的顶点访问完为止。 入度…...
2023最新版!宝塔面板Docker自建Bitwarden密码管理
Powered by:NEFU AB-IN 请一定要结合B站视频食用!!!!,下面的博客总体来说只是起到提纲作用 B站视频链接!!! 文章目录2023最新版!宝塔面板Docker自建Bitwarden密码管理前…...
【Hello Linux】 Linux基础命令
作者:小萌新 专栏:Linux 作者简介:大二学生 希望能和大家一起进步! 本篇博客简介:介绍Linux的基础命令 Linux基础命令ls指令lsls -als -dls -ils -sls -lls -nls -Fls -rls -tls -Rls -1总结思维导图pwd指令whoami指令…...
151、【动态规划】leetcode ——2. 01背包问题:二维数组+一维数组(C++版本)
题目描述 原题链接:2. 01背包问题 解题思路 (1)二维dp数组 动态规划五步曲: (1)dp[i][j]的含义: 容量为j时,从物品1-物品i中取物品,可达到的最大价值 (2…...
2023-02-09 - 3 Elasticsearch基础操作
本章主要介绍ES的基础操作,具体包括索引、映射和文档的相关操作。其中,在文档操作中将分别介绍单条操作和批量操作。在生产实践中经常会通过程序对文档进行操作,因此在介绍文档操作时会分别介绍DSL请求形式和Java的高级REST编码形式。 1 索引…...
云原生系列之使用 prometheus监控MySQL实战
文章目录前言一. 实验环境二. 安装MySQL5.72.1 配置yum源2.2 安装MySQL之前的环境检查2.3 开始使用yum安装2.4 启动MySQL并测试三. 安装MySQL_exporter3.1 MySQL_exporter的介绍3.2 mysql_exporter的安装3.3 设置MySQL账户,用于数据收集3.4 启动mysql_exporter3.5 配…...
电脑分盘怎么分?分盘详细教程来了,图文教学
电脑作为小伙伴日常生活使用的工具,很多事情都需要使用电脑来进行处理。虽然小伙伴使用电脑比较多,但是还是有不少的小伙伴不知道电脑分盘怎么分?其实电脑分盘很简单,下面小编就以图文教学的方式,详细的向小伙伴介绍电…...
Element UI框架学习篇(四)
Element UI框架学习篇(四) 1 准备工作 1.0 创建Emp表并插入相应数据的sql语句 /*MySQL数据库*/SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS 0;-- ---------------------------- -- Table structure for emp -- ---------------------------- DROP TABLE IF EXISTS emp; CRE…...
Revit快速材质切换:同一墙面赋予不同材质的方法
一、Revit中对同一墙面赋予不同材质的方法 方法1:零件法 重点:通过工作平面面板上的设置工作平面命令选取正确的面取消勾选通过原始分类的材质,如图1所示 方法2:拆分构造层绘制一道墙体,选择创建的墙体,单击…...
临汾网站建设 吕梁网站建设/开鲁网站seo免费版
默认情况下,Java类的反射对象并未包含方法入参的名称,如果编译时打开debug开关(javac-debugno),则方法入参名也会记录到类的反射对象中,所有如果PathVariable注解后面不指定参数的时候,要使方法…...
ih5网站制作平台/百度高级搜索入口
可能是防火墙的问题: 怎么打开防火墙:控制面板--Windows防火墙--允许程序或者功能通过防火墙--允许运行另一程序 找到你需要允许程序的路径,添加进去就可以啦。...
深圳做网站优化费用/广州网站优化公司排名
【摘 要】随着人们生活水平的不断提高,家用轿车保有量每年都在不断的攀升,导致城市交通问题日益突出。为缓解城市停车难的问题,本文提出了基于android平台下开发的共享停车系统app,意在帮助用户在高峰期劈开停车难的问题ÿ…...
网站 粘度/深圳网站建设资讯
显示存储卷列表(和nova volume-list命令功能相同) cinder list 显示存储卷类型列表 cinder type-list 列表展示zone cinder availability-zone-list 创建存储卷 cinder create --display-name VOLNAME SIZE(SIZE的单位为GB) 创建基…...
wordpress get_search_form()/什么是百度搜索推广
MMA7660加速计驱动 1、MMA7660介绍 MMA7660FC 是一款数字输出 IC、超低功耗、薄型电容式微加工加速度计,具有低通滤波器、零重力偏移和增益误差补偿以及用户可配置输出数据转换为六位数字值速度。 该器件可通过中断引脚 (INT) 用于传感器数据更改、产品方向和手势检测。 I2C…...
服务器搭建网站空间/推广点击器
题目链接 输出为三部分:星期、小时、分钟组成。 星期:由前两个字符串对应位置的第一组相同的大写字母表示,{"MON","TUE","WED","THU","FRI","SAT","SUN"}对应A到G。…...