Hooks与普通函数的区别
Hooks与普通函数的区别
在这里的Hooks具体指的是自定义Hooks,自定义的Hooks与我们定义的普通函数类似,都可以封装逻辑,以实现逻辑的复用。Hooks实际上是一种特殊的函数,而由于Hooks的特殊实现,他们之间也存在着一定的区别。
描述
在我开始学习React Hooks的时候,我就比较疑惑这个问题。首先看一下官方文档,在自定义Hooks的部分说明了,构建自己的Hooks可以让您将组件逻辑提取到可重用的函数中。如果仅仅是这样的话,那么我们也完全可以使用普通的函数来实现逻辑的复用,而没必要去使用Hooks了。
当然在这里还是得先明确一点定义: 自定义Hooks就是很明确的定义了,其以use开头,内部可以调用其他的Hooks;在这里描述的的普通函数指的是我们平时写的抽离公共逻辑的函数,而不是在我们定义的普通函数中去调用其他Hooks这种方式。如果在普通函数中调用了其他Hooks,那么这个函数就不再是普通函数了,除了违反了Hooks的命名规则以外,那就完全是一个Hooks的定义了。
实际上,Coding比较重要的两个概念是逻辑与数据,文档中提到的将组件逻辑提取到可重用的函数中,重要的是逻辑这两个字,而在两个组件中使用相同的自定义Hooks是不会共享State的。如果我们直接编写一个普通的函数,那么对于其数据是在所有调用者中共享的,因为其只是一个模块,当然前提是我们不会去new出一个新对象来保存状态,在这里只讨论最plain的调用方式,因为Hooks也是直接以非常plain的方式进行调用的。
那么也就是说,如果我们使用Hooks的话,实际上由于可以调用useState、useRef等Hooks,从而获取了对于这个Fiber的访问方法,那么也就相当于我们可以将状态或者说数据存放于当前节点当中,而不是类似于普通函数在全局中共享。当然如果需要全局共享状态的话,状态管理方案是更好的选择,而不是全局变量。
示例
举一个例子,对于数据请求,我们通常会封装一个request函数,假如我们需要对这个函数做一层缓存,那么就会有逻辑与数据的复用,在逻辑方面我们抽离出的方法差距不大,而对于数据缓存复用方面在这里通过普通函数与自定义Hooks的实现便是不同的。
普通函数
在普通函数当中,其就是一个模块,因此其数据是在所有调用者中共享的,因此我们可以通过一个Map来存储数据,这样就可以实现数据的复用。在这里需要注意的是,如果我们的url需要实现在不同组件调用返回的数据不同的话,例如可能会有根据当前页面的referer请求头来决定返回数据的需求,那么这种全局共享的数据就不适用了,就需要多添加一个参数来区分不同的数据,这样就会导致逻辑与数据的耦合,因此这种方式不是很好。当然这也是基于特定需求的,在这里只是举一个例子,毕竟实际上适合的才是最好的。
const cache = new Map();
export fetch = (url) => {
if (cache.has(url)) {
return cache.get(url);
}
const promise = fetch(url);
cache.set(url, promise);
return promise;
}
自定义Hooks
在自定义Hooks当中,数据被锁定在了Fiber当中,也就是说数据的共享范围是在当前组件节点中,相对于全局状态共享来说粒度会更细一些。当然我们如果想直接在全局共享数据的话,这种方案就不合适了,可能还需要配合一个全局的状态管理才行。还是那句话,在这里只是举一个例子,毕竟实际上适合的才是最好的。
const useRequest = (url) => {
const map = useRef(new Map());
if (map.current.has(url)) {
return map.current.get(url);
}
const promise = fetch(url);
map.current.set(url, promise);
return promise;
}
总结
简单总结一下两者的区别:
- 官方提供的
Hooks只应该在React函数组件/自定义Hooks内调用,而不应该在普通函数调用。 - 自定义
Hooks能够调用诸如useState、useRef等,普通函数则不能。由此可以通过内置的Hooks获得Fiber的访问方式,可以实现在组件级别存储数据的方案等。 - 自定义
Hooks需要以use开头,普通函数则没有这个限制。使用use开头并不是一个语法或者一个强制性的方案,更像是一个约定,就像是GET请求约定语义不携带Body一样,使用use开头的目的就是让React识别出来这是个Hooks,从而检查这些规则约束,通常也会使用ESlint配合eslint-plugin-react-hooks检查这些规则,从而提前避免错误的使用。
每日一题
https://github.com/WindrunnerMax/EveryDay
参考
https://www.zhihu.com/question/491311403
https://zh-hans.reactjs.org/docs/hooks-custom.html
https://stackoverflow.com/questions/60133412/react-custom-hooks-vs-normal-functions-what-is-the-difference
Hooks与普通函数的区别的更多相关文章
- PHP中fopen,file_get_contents,curl函数的区别
PHP中fopen,file_get_contents,curl函数的区别 1.fopen/file_get_contents每次请求都做DNS查询,并不对DNS的信息进行缓存,而curl会对DNS的 ...
- php正规则表达式学习笔记(几个常用函数的区别)
preg_mache()函数和 preg_mache_all()函数的区别: preg_mache()只会匹配规则中的字符一次, preg_mache_all()会匹配符合条件的所有字符! 例子对比: ...
- SQL表值函数和标量值函数的区别
SQL表值函数和标量值函数的区别 写sql存储过程经常需要调用一些函数来使处理过程更加合理,也可以使函数复用性更强,不过在写sql函数的时候可能会发现,有些函数是在表值函数下写的有些是在标量值下写的, ...
- exit()与_exit()函数的区别(Linux系统中)
注:exit()就是退出,传入的参数是程序退出时的状态码,0表示正常退出,其他表示非正常退出,一般都用-1或者1,标准C里有EXIT_SUCCESS和EXIT_FAILURE两个宏,用exit(EXI ...
- fork 函数 和vfork 函数的区别
问题描述: fork 函数 和vfork 函数的区别 问题解决: fork函数使用: 注: 以上printf 属于标准IO库带缓冲,如果标准输出链接到终端设备,则它是行 ...
- sql - sum() 和 count() 函数的区别
对sql一直都是蜻蜓点水,突然也觉得对这两个函数的区别有点朦胧,查了一下,在这里说一下: sum():主要用于累加求和. count():主要用于行(记录)的统计.
- php中strstr、strrchr、substr、stristr四个函数的区别总结
php中strstr.strrchr.substr.stristr四个函数的区别总结 投稿:junjie 字体:[增加 减小] 类型:转载 时间:2014-09-22我要评论 这篇文章主要介绍了php ...
- 引用 exit、return、_exit、_Exit这几个函数的区别
引用 exit.return._exit._Exit这几个函数的区别 一.exit函数和return函数的主要区别是: exit用于在程序运行的过程中随时结束程序,其参数是返回给OS的.也可以这么讲: ...
- php中strstr、strrchr、substr、stristr四个函数用法区别
php中strstr.strrchr.substr.stristr四个函数用法区别: php中strstr strrchr substr stristr这四个字符串操作函数特别让人容易混淆,常用的是s ...
- static函数和普通函数的区别
static函数与普通函数的区别: 用static修饰的函数,本限定在本源码文件中,不能被本源码文件以外的代码文件调用.而普通的函数,默认是extern的,也就是说,可以被其它代码文件调用该函数. 在 ...
随机推荐
- 【SHELL】在指定格式的文件中查找字符串
在指定格式的文件中查找字符串 grep -nr "string" --include=*.{c,cpp,h} 在排除指定格式的文件中查找字符串 grep -nr "str ...
- javaweb 项目!号 解决方案
1:右击项目工程名称2:Properties3: Jvav Build Path4: Libraries5: Add External JARS6: 找到"E:\apache-tom ...
- [转帖]Linux中的lstopo命令(详细指南)
https://juejin.cn/post/7117544110856077343 目录: 简介 语法 命令 总结 参考文献 介绍 lstopo命令是用来显示系统的拓扑结构的.它提供了关于NUMA内 ...
- [转帖]实践真知:解决 Jdbc 连接 Oracle 12c 时快时慢的问题
https://cloud.tencent.com/developer/article/1052506 李真旭@killdb Oracle ACE,云和恩墨技术专家 个人博客:www.killdb.c ...
- [转帖]国产数据库到底行不行?人大金仓KINGBASE数据库与主流开源数据库性能实测
近年来,人大金仓的数据库产品受到了外界诸多的关注.做产品,免不了要接受用户的对比和选择,数据库因其行业的自身特点,还有很多开源的技术产品同台比拼,用户因此也会产生诸多疑问,国产数据库相比开源数据库到底 ...
- [转帖]【Kafka】(二)Kafka去Zookeeper化,kraft模式搭建
1.简介 由于zookeeper慢慢的成了kafka的瓶颈,kafka提出了去zookeeper化的概念,并在2.8版本之后版本都包含了kraft模式,也就是不需要使用zookeeper了,目前这种模 ...
- [转帖]人脸特征计算速度优化-SIMD技术Neon介绍
人脸特征计算速度优化-SIMD技术Neon介绍 JasonZhu 游走于秃头和研究的边缘 关注 15 人赞同了该文章 目录 收起 1. baseline计算 2. simd和数据重排加速 数 ...
- Linux bridge使用dummy接口调用IPVS的问题
Linux bridge使用dummy接口调用IPVS的问题 在IPVS: How Kubernetes Services Direct Traffic to Pods一文中,作者给出了一个简单的组网 ...
- 我对vue3的理解
我对 reactive源码的理解 reactive 只能够代理对象 首先它判断传递过来的值是否是对象,如果是才会进行代理.变成响应式的. Proxy 并没有重写对象的属性,只做代理,在取值的时候回调用 ...
- c#通过表达式树优雅的实现分组取TopN笔记
需要引入nuget包来实现ef.functions调用row_number Thinktecture.EntityFrameworkCore.SqlServer 调用方式: //顺排 context. ...