当前位置:网站首页>通过这两个 hook 回顾 Set/Map 基础知识
通过这两个 hook 回顾 Set/Map 基础知识
2022-08-01 20:58:00 【GopalFeng】
本文是深入浅出 ahooks 源码系列文章的第十篇,这个系列的目标主要有以下几点:
- 加深对 React hooks 的理解。
- 学习如何抽象自定义 hooks。构建属于自己的 React hooks 工具库。
- 培养阅读学习源码的习惯,工具库是一个对源码阅读不错的选择。
今天我们来聊聊 ahooks 中对 Map 和 Set 类型进行状态管理的 hook,顺便复习一下 Set 和 Map 这两种数据类型。
useMap
管理 Map 类型状态的 Hook。
先回顾以下 Map 的概念。Map 对象保存键值对,并且能够记住键的原始插入顺序。任何值(对象或者基本类型)都可以作为一个键或一个值。
Object 和 Map 很类似。它们都允许你按键存取一个值、删除键、检测一个键是否绑定了值。因此过去我们一直都把对象当成 Map 使用。
但是,在一些场景下,使用 Map 是更优的选择,以下是一些常见的点:
- 键值的类型。一个 Map 的键可以是任意值,包括函数、对象或任意基本类型。一个 Object 的键必须是一个 String 或是 Symbol。
- 需要保证键值的顺序。Map 中的键是有序的。因此,当迭代的时候,一个 Map 对象以插入的顺序返回键值。虽然 Object 的键目前是有序的,但并不总是这样,而且这个顺序是复杂的。因此,最好不要依赖属性的顺序。
- Size。Map 的键值对个数可以轻易地通过 size 属性获取。Object 的键值对个数只能手动计算。比如遍历对象属性,计算它的个数。
- 性能。Map 在频繁增删键值对的场景下表现更好。Object 在频繁添加和删除键值对的场景下未作出优化。
更多,可以看 Objects 和 maps 的比较[1]。
我们来看下 ahooks 做了哪些封装,同时回顾以下 Map 的一些基础 API 用法。
首先是默认值的设置,通过 Map 构造函数 new Map() 创建 Map 对象。入参为默认值。
function useMap<K, T>(
// 传入默认的 Map 参数
initialValue?: Iterable<readonly [K, T]>,
) {
const getInitValue = () => {
return initialValue === undefined ? new Map() : new Map(initialValue);
};
const [map, setMap] = useState<Map<K, T>>(() => getInitValue());
// 省略代码...
}
set 方法。添加 Map 新的 key 和 value 或者更新 key 的值,因为 React 是不可变数据,需要要返回一个全新的值,所以需要创建一个新的 Map 对象。
通过 Map 的 set 方法,在 Map 对象中设置与指定的键 key 关联的值 value,并返回 Map 对象。
// 添加 map
const set = (key: K, entry: T) => {
setMap((prev) => {
const temp = new Map(prev);
temp.set(key, entry);
return temp;
});
};
remove 方法。通过 Map 的 delete 方法,移除 Map 对象中指定的键值对,如果键值对存在并成功被移除,返回 true,否则返回 false。调用 delete 后再调用 Map.prototype.has(key) 将返回 false。
// 移除
const remove = (key: K) => {
setMap((prev) => {
const temp = new Map(prev);
temp.delete(key);
return temp;
});
};
- setAll 方法。传入一个全新的 Map 对象,直接覆盖旧的 Map 对象。
- reset 方法。重置 Map 对象为初始值。在 Map 中有一个 clear 的方法,它移除 Map 对象中所有的键值对,相比 clear,reset 方法更贴近我们的需求。
- get 方法,通过 Map 的 get 方法,返回与 key 关联的值,若不存在关联的值,则返回 undefined。
// 生成一个新的 Map 对象
const setAll = (newMap: Iterable<readonly [K, T]>) => {
setMap(new Map(newMap));
};
// 重置
const reset = () => setMap(getInitValue());
// 获取
const get = (key: K) => map.get(key);
对于一些其他没有副作用的方法,ahooks 没有封装,我觉得是合理的,这些在开发者想用的时候,直接调用就可以了。
- has(key)。返回一个布尔值,用来表明 Map 对象中是否存在与 key 关联的值。
- keys()。返回一个新的迭代对象,其中包含 Map 对象中所有的键,并以插入 Map 对象的顺序排列。
- values()。返回一个新的迭代对象,其中包含 Map 对象中所有的值,并以插入 Map 对象的顺序排列。
- entries()。返回一个新的迭代对象,其为一个包含 Map 对象中所有键值对的 [key, value] 数组,并以插入 Map 对象的顺序排列。
useSet
管理 Set 类型状态的 Hook。
直接看代码。
默认值的设置,通过 new Set() 构造函数,创建一个新的 Set 对象。
function useSet<K>(initialValue?: Iterable<K>) {
const getInitValue = () => {
return initialValue === undefined ? new Set<K>() : new Set(initialValue);
};
const [set, setSet] = useState<Set<K>>(() => getInitValue());
// 省略一些代码
}
add 方法添加一个元素。调用 Set 的 add 方法,在 Set 对象尾部添加一个元素。返回该 Set 对象。
const add = (key: K) => {
if (set.has(key)) {
return;
}
setSet((prevSet) => {
const temp = new Set(prevSet);
temp.add(key);
return temp;
});
};
remove 方法移除一个元素。调用 Set 的 delete(value) 方法,移除 Set 中与这个值相等的元素,返回 Set.prototype.has(value) 在这个操作前会返回的值(即如果该元素存在,返回 true,否则返回false)。Set.prototype.has(value) 在此后会返回 false。
// 移除
const remove = (key: K) => {
if (!set.has(key)) {
return;
}
setSet((prevSet) => {
const temp = new Set(prevSet);
temp.delete(key);
return temp;
});
};
reset 方法,重置 Set 回默认值。其对应的 Set 的 clear 方法,会移除Set对象内的所有元素。
// 重置
const reset = () => setSet(getInitValue());
其他 Set 方法:
- entries()。返回一个新的迭代器对象,该对象包含 Set 对象中的按插入顺序排列的所有元素的值的 [value, value] 数组。为了使这个方法和 Map 对象保持相似, 每个值的键和值相等。
- has(value)。返回一个布尔值,表示该值在 Set 中存在与否。
- keys() 和 values()。都返回一个新的迭代器对象,该对象包含 Set 对象中的按插入顺序排列的所有元素的值。
- forEach(callbackFn[, thisArg])。按照插入顺序,为 Set 对象中的每一个值调用一次 callBackFn。如果提供了thisArg参数,回调中的 this 会是这个参数。
思考与总结
ES6 中的 Map 和 Set 两种数据结构,弥补了 JavaScript 之前的一些不足,比如 Object 对象只能是 string 或者 Symbol 类型。另外,提供了某些情况下更便捷的操作方式,比如数组去重,我们可以直接 new Set([...arr])。
现在越来越多的场景使用了 Map 和 Set,ahooks 对这两者的封装都比较简单,更多的是一些有副作用(修改到原 Map 和 Set)操作的封装。看这部分的源码,就当做小小复习基础知识吧。
系列文章:
- 大家都能看得懂的源码(一)ahooks 整体架构篇[2]
- 如何使用插件化机制优雅的封装你的请求hook [3]
- ahooks 是怎么解决 React 的闭包问题的?[4]
- ahooks 是怎么解决用户多次提交问题?[5]
- ahooks 中那些控制“时机”的hook都是怎么实现的?[6]
- 如何让 useEffect 支持 async...await?[7]
- 如何让定时器在页面最小化的时候不执行?[8]
- 记录第一次给开源项目提 PR[9]
参考资料
[1]Objects 和 maps 的比较: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Map#objects_%E5%92%8C_maps_%E7%9A%84%E6%AF%94%E8%BE%83
[2]大家都能看得懂的源码(一)ahooks 整体架构篇: https://juejin.cn/post/7105396478268407815
[3]如何使用插件化机制优雅的封装你的请求hook : https://juejin.cn/post/7105733829972721677
[4]ahooks 是怎么解决 React 的闭包问题的?: https://juejin.cn/post/7106061970184339464
[5]ahooks 是怎么解决用户多次提交问题?: https://juejin.cn/post/7106461530232717326
[6]ahooks 中那些控制“时机”的hook都是怎么实现的?: https://juejin.cn/post/7107189225509879838
[7]如何让 useEffect 支持 async...await?: https://juejin.cn/post/7108675095958126629
[8]如何让定时器在页面最小化的时候不执行?: https://juejin.cn/post/7109399243202232357
[9]记录第一次给开源项目提 PR: https://juejin.cn/post/7110144695098933284
边栏推荐
- 有用的网站
- 微服务负载均衡器Ribbon
- "Torch" tensor multiplication: matmul, einsum
- [Multi-task learning] Modeling Task Relationships in Multi-task Learning with Multi-gate Mixture-of-Experts KDD18
- Kubernetes 如何实现组件高可用
- Little data on how to learn?Jida latest small learning data review, 26 PDF page covers the 269 - page document small data learning theory, method and application are expounded
- idea插件generateAllSetMethod一键生成set/get方法以及bean对象转换
- 响应式织梦模板清洁服务类网站
- Zheng Xiangling, Chairman of Tide Pharmaceuticals, won the "2022 Outstanding Influential Entrepreneur Award" Tide Pharmaceuticals won the "Corporate Social Responsibility Model Award"
- Simple test of the use of iptables
猜你喜欢

Use WeChat official account to send information to designated WeChat users

STAHL touch screen repair all-in-one display screen ET-316-TX-TFT common faults

【Kaggle】Classify Leaves

vant实现Select效果--单选和多选

使用百度EasyDL实现厂区工人抽烟行为识别

STAHL触摸屏维修一体机显示屏ET-316-TX-TFT常见故障

idea插件generateAllSetMethod一键生成set/get方法以及bean对象转换
![[Personal work] Wireless network image transmission module](/img/64/c0cec74692df7ca05c1a5317e21c9d.png)
[Personal work] Wireless network image transmission module

Application of Acrel-5010 online monitoring system for key energy consumption unit energy consumption in Hunan Sanli Group

Acrel-5010重点用能单位能耗在线监测系统在湖南三立集团的应用
随机推荐
技能大赛训练:A部分加固题目
Software you should know as a programmer
微信小程序云开发|个人博客小程序
任务调度线程池-应用定时任务
使用员工管理软件,解锁人力生产力新水平,提高人力资源团队灵活性
Go Atomic
织梦模板加入php代码
Fork/Join线程池
WhatsApp group sending actual combat sharing - WhatsApp Business API account
线上问题排查常用命令,总结太全了,建议收藏!!
[Multi-task learning] Modeling Task Relationships in Multi-task Learning with Multi-gate Mixture-of-Experts KDD18
SkiaSharp 之 WPF 自绘 五环弹动球(案例版)
MongoDB快速上手
数字孪生北京故宫,元宇宙推进旅游业进程
Based on FPGA in any number of bytes (single-byte or multibyte) serial port (UART) to send (including source engineering)
Questions I don't know in database kernel interview(1)
LeetCode每日一题(1807. Evaluate the Bracket Pairs of a String)
[Energy Conservation Institute] Comparative analysis of smart small busbar and column head cabinet solutions in data room
New graduate students, great experience in reading English literature, worthy of your collection
织梦发布文章提示body has not allow words错误