本文是深入浅出 ahooks 源码系列文章的第十篇,该系列已整理成文档-地址。觉得还不错,给个 star 支持一下哈,Thanks。

今天我们来聊聊 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 的比较

我们来看下 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 useSet 和 useMap的更多相关文章

  1. 大家都能看得懂的源码 - ahooks 是怎么处理 DOM 的?

    本文是深入浅出 ahooks 源码系列文章的第十三篇,该系列已整理成文档-地址.觉得还不错,给个 star 支持一下哈,Thanks. 本篇文章探讨一下 ahooks 对 DOM 类 Hooks 使用 ...

  2. 大家都能看得懂的源码(一)ahooks 整体架构篇

    本文是深入浅出 ahooks 源码系列文章的第一篇,该系列已整理成文档-地址.觉得还不错,给个 star 支持一下哈,Thanks. 第一篇主要介绍 ahooks 的背景以及整体架构. React h ...

  3. 大家都能看得懂的源码 - 如何封装 cookie/localStorage/sessionStorage hook?

    本文是深入浅出 ahooks 源码系列文章的第九篇,该系列已整理成文档-地址.觉得还不错,给个 star 支持一下哈,Thanks. 今天来看看 ahooks 是怎么封装 cookie/localSt ...

  4. 大家都能看得懂的源码 - 那些关于DOM的常见Hook封装(一)

    本文是深入浅出 ahooks 源码系列文章的第十四篇,该系列已整理成文档-地址.觉得还不错,给个 star 支持一下哈,Thanks. 上一篇我们探讨了 ahooks 对 DOM 类 Hooks 使用 ...

  5. 大家都能看得懂的源码之ahooks useInfiniteScroll

    本文是深入浅出 ahooks 源码系列文章的第十七篇,该系列已整理成文档-地址.觉得还不错,给个 star 支持一下哈,Thanks. 简介 useInfiniteScroll 封装了常见的无限滚动逻 ...

  6. 大家都能看得懂的源码 - 那些关于DOM的常见Hook封装(二)

    本文是深入浅出 ahooks 源码系列文章的第十五篇,该系列已整理成文档-地址.觉得还不错,给个 star 支持一下哈,Thanks. 本篇接着针对关于 DOM 的各个 Hook 封装进行解读. us ...

  7. 大家都能看得懂的源码之 ahooks useVirtualList 封装虚拟滚动列表

    本文是深入浅出 ahooks 源码系列文章的第十八篇,该系列已整理成文档-地址.觉得还不错,给个 star 支持一下哈,Thanks. 简介 提供虚拟化列表能力的 Hook,用于解决展示海量数据渲染时 ...

  8. 如何读懂Framework源码?如何从应用深入到Framework?

    如何读懂Framework源码? 首先,我也是一个应用层开发者,我想大部分有"如何读懂Framework源码?"这个疑问的,应该大都是应用层开发. 那对于我们来讲,读源码最大的问题 ...

  9. <转>如何高效快速看懂Android源码

    原网址:http://jingyan.baidu.com/article/574c5219ca78ed6c8d9dc12a.html 在Android系统上工作了一段时间,经常会遇到题目中的问题,下面 ...

随机推荐

  1. MySQL之事务隔离级别和MVCC

    事务隔离级别 事务并发可能出现的问题 脏写 事务之间对增删改互相影响 脏读 事务之间读取其他未提交事务的数据 不可重复读 一个事务在多次执行一个select读到的数据前后不相同.因为被别的未提交事务修 ...

  2. Vue出现Component template should ...

    当运行vue出现错误Component template should contain exactly one root element. If you ...的时候,我们只需要将<templa ...

  3. 抽象类与接口——JavaSE基础

    抽象类与接口 抽象类 抽象类既包含规范又包含具体实现 抽象类可以包含实现的方法 和 未实现的用abstract修饰的抽象方法 抽象类不可以有实例化(不能使用new实例化),只能通过子类继承,然后对子类 ...

  4. SAP Web Dynpro-门户集成

    您可以将ABAP应用程序集成到企业门户中. 您还可以从Web Dynpro应用程序管理门户网站功能. 您可以调用Web Dynpro代码向导来访问门户网站管理器方法. 这可以用来执行以下功能- 门户网 ...

  5. React技巧之处理tab页关闭事件

    原文链接:https://bobbyhadz.com/blog/react-handle-tab-close-event 作者:Borislav Hadzhiev 正文从这开始~ 总览 在React中 ...

  6. css-sticky 定位

    前言 我们大多都了解绝对定位.相对定位.static 和 fixed 定位,而 sticky 定位常常会被忽略,本文来总结一下其相关使用方法. 正文 1.常见使用效果 我们滚动滚动条时,当 " ...

  7. 实现一个Prometheus exporter

    Prometheus 官方和社区提供了非常多的exporter,涵盖数据库.中间件.OS.存储.硬件设备等,具体可查看exporters.exporterhub.io,通过这些 exporter 基本 ...

  8. NC50965 Largest Rectangle in a Histogram

    NC50965 Largest Rectangle in a Histogram 题目 题目描述 A histogram is a polygon composed of a sequence of ...

  9. dolphinscheduler简单任务定义及复杂的跨节点传参

    dolphinscheduler简单任务定义及跨节点传参 转载请注明出处 https://www.cnblogs.com/funnyzpc/p/16395094.html 写在前面 dolphinsc ...

  10. 研发效能生态完整图谱&DevOps工具选型必看

    本文主要梳理了研发效能领域完整的方向图谱以及主流工具,其中对少部分工具也做了一些点评.看了之后,大家可以对研发效能这个领域有个整体认识,同时研发效能落地的时候也有对应的工具(黑话叫抓手)可以选择. 我 ...