当前位置: 首页 > Web前端 > JavaScript

大家看得懂的源码——ahooks的useSet和useMap

时间:2023-03-27 13:40:58 JavaScript

本文是深入浅出的ahooks源码系列文章的第十篇。本系列已整理成文档地址。觉得还不错,点个赞支持一下,谢谢。今天我们就来说说ahooks中管理Map和Set类型状态的hook,顺便复习一下Set和Map这两种数据类型。useMap是一个管理Map类型状态的Hook。下面先回顾一下Map的概念。映射对象保存键值对并且能够记住键的原始插入顺序。任何值(对象或原始类型)都可以用作键或值。对象类似于地图。它们都允许您通过键访问值、删除键以及检查键是否绑定到值。所以过去我们一直使用对象作为Map。但是在某些场景下,使用Map是更好的选择,以下是一些共同点:keyvalue的类型。Map的键可以是任何值,包括函数、对象或任何原始类型。对象的键必须是字符串或符号。需要保证键值的顺序。Map中的键是有序的。因此,在迭代时,Map对象按插入顺序返回键。虽然Object的键当前是有序的,但情况并非总是如此,而且这种排序很复杂。因此,最好不要依赖属性的顺序。尺寸。Map中键值对的个数可以很容易的通过size属性获取。Object的key-value对的个数只能手动计算。比如遍历对象属性,计算其个数。表现。Map在频繁增删键值对的场景下表现更好。对象未针对频繁添加和删除键值对进行优化。有关更多信息,请参阅对象和地图的比较。我们先看看封装ahooks做了什么,再回顾下Map的一些基本API用法。首先是默认值的设置,通过Map构造函数newMap()创建Map对象。输入参数为默认值。functionuseMap(//传入默认的Map参数initialValue?:Iterable,){constgetInitValue=()=>{returninitialValue===undefined?新地图():新地图(初始值);};const[map,setMap]=useState>(()=>getInitValue());//代码省略...}set方法。向Map添加新的键和值或更新键的值。因为React是不可变数据,需要返回一个新的值,所以需要创建一个新的Map对象。通过Map的set方法设置Map对象中指定键key关联的值,返回Map对象。//添加mapconstset=(key:K,entry:T)=>{setMap((prev)=>{consttemp=newMap(prev);temp.set(key,entry);returntemp;});};删除方法。通过Map的delete方法删除Map对象中指定的键值对。如果键值对存在且移除成功,则返回true,否则返回false。调用delete后跟Map.prototype.has(key)将返回false。//删除constremove=(key:K)=>{setMap((prev)=>{consttemp=newMap(prev);temp.delete(key);returntemp;});};setAll方法。传入一个全新的Map对象,直接覆盖旧的Map对象。重置方法。将Map对象重置为其初始值。Map中有一个clear方法,就是移除Map对象中的所有键值对。相比clear,reset方式更贴近我们的需求。get方法通过Map的get方法返回key关联的值,没有关联值则返回undefined。//生成一个新的Map对象constsetAll=(newMap:Iterable)=>{setMap(newMap(newMap));};//重置constreset=()=>setMap(getInitValue());//获取constget=(key:K)=>map.get(key);其他一些没有副作用的方法,ahooks没有封装,我觉得也是合理的,这些都是开发者要用的,直接调用就行了。有(钥匙)。返回一个布尔值,指示与键关联的值是否存在于Map对象中。钥匙()。返回一个新的可迭代对象,其中包含Map对象中的所有键,按照它们插入Map对象的顺序。价值观()。返回一个新的迭代器对象,其中包含Map对象中的所有值,按照它们被插入Map对象的顺序排列。条目()。返回一个新的迭代器对象,它是一个[key,value]数组,包含Map对象中的所有键值对,按照插入Map对象的顺序排列。useSet管理Set类型状态的Hook。直接看代码。要设置默认值,请通过新的Set()构造函数创建一个新的Set对象。函数useSet(initialValue?:Iterable){constgetInitValue=()=>{returninitialValue===undefined?newSet():newSet(initialValue);};const[set,setSet]=useState>(()=>getInitValue());//省略一些代码}add方法添加一个元素。调用Set的add方法在Set对象的末尾添加一个元素。返回此Set对象。constadd=(key:K)=>{if(set.has(key)){返回;}setSet((prevSet)=>{consttemp=newSet(prevSet);temp.add(key);returntemp;});};remove方法删除一个元素。调用Set的delete(value)方法删除Set中等于该值的元素,并返回本次操作前Set.prototype.has(value)将返回的值(即元素存在则返回true,否则返回假)。Set.prototype.has(value)之后将返回false。//移除constremove=(key:K)=>{if(!set.has(key)){return;}setSet((prevSet)=>{consttemp=newSet(prevSet);temp.delete(key);returntemp;});};reset方法,将Set重置为默认值。Set对应的clear方法会清除Set对象中的所有元素。//重置constreset=()=>setSet(getInitValue());其他Set方法:entries()。返回一个新的迭代器对象,其中包含按插入顺序排列的Set对象中所有元素的值的[value,value]数组。为了使此方法与Map对象相似,每个值的键和值都相等。有(价值)。返回一个布尔值,指示该值是否存在于Set中。键()和值()。两者都返回一个新的迭代器对象,其中包含按插入顺序排列的Set对象中所有元素的值。forEach(callbackFn[,thisArg])。按插入顺序为Set对象中的每个值调用一次CallBackFn。如果提供了thisArg参数,回调中的this就是这个参数。思考总结ES6中的Map和Set数据结构,弥补了JavaScript的一些不足,比如Object对象只能是string或者Symbol类型。另外,它在某些情况下提供了更方便的操作方法,比如数组的去重,我们可以直接newSet([...arr])。现在越来越多的场景使用Map和Set。ahooks对两者的封装都比较简单,更多的是对有副作用的操作的封装(对原有Map和Set的修改)。看这部分源码,只是作为基础的小回顾。本文已收录在我的个人博客中,欢迎关注~