useSet
簡介
首先,set是es6新增的資料結構,類似陣列,但set不能有相同的成員,可以利用這點來給陣列去重;在set內新增成員比array快,但set在排序上不如陣列靈活。
useSet是一個用來管理set型別state的hook,封裝了以下幾個功能:
- add:增加元素
- remolve:刪除某個元素
- reset:重置回初始狀態
簡單示例
const [set,{add,remove,reset}
] = useSet<string>(['a','b']);//set為['a','b']
add('c')//set為['a','b','c']
remolve('b')//set為['a','c']
reset()//set為['a','b']
原始碼分析
import { useState } from 'react';
import useMemoizedFn from '../useMemoizedFn';
function useSet<K>(initialValue?: Iterable<K>) {
//獲取初始值:使用new Set建立一個以初始傳入引數為內容的set,或者一個空set
const getInitValue = () => {
return initialValue === undefined ? new Set<K>() : new Set(initialValue);
};
//用基本的useState來封裝該hook
const [set, setSet] = useState<Set<K>>(() => getInitValue());
//add方法:若set已有該值,則不做處理;若無,則使用set的add方法新增元素
const add = (key: K) => {
if (set.has(key)) {
return;
}
setSet((prevSet) => {
const temp = new Set(prevSet);
temp.add(key);
return temp;
});
};
//remove方法:若set沒有該值,則不做處理;若無,則使用set的delete方法刪除元素
const remove = (key: K) => {
if (!set.has(key)) {
return;
}
setSet((prevSet) => {
const temp = new Set(prevSet);
temp.delete(key);
return temp;
});
};
//reset方法:重置回初始值
const reset = () => setSet(getInitValue());
//返回使用了useMemoizedFn這個hook
return [
set,
{
add: useMemoizedFn(add),
remove: useMemoizedFn(remove),
reset: useMemoizedFn(reset),
},
] as const;
}
export default useSet;
要點分析
該hook在return方法的時候使用了useMemoizedFn這個hook。該hook和useCallback類似。
但不同之處在於useCallback返回的是回撥函式的memoized版本,當依賴項不改變的時候,它不會更新函式,但新增依賴項的時候,函式會重新渲染,這就失去了快取函式的意義;而useMemoizedFn解決了這個問題,可以用來快取各種函式,並且函式的地址不會被改變。
基於useSet的改寫:useArray,實現了陣列的push、pop、shift、unshift方法
在使用useSet的過程中,由於useSet的add方法是將元素直接加在set的後面,感覺想要將元素插在set前面不太靈活,於是照著該原始碼,簡單地改編了一個useArray,實現了陣列的push、pop、shift、unshift方法。
程式碼如下:
import { useState } from 'react';
import { useMemoizedFn } from 'ahooks';
function useArray<K>(initialValue?: Iterable<K>) {
const getInitValue = () => {
return initialValue === undefined ? new Array<K>() : Array.from(initialValue);
};
const [array, setArray] = useState<Array<K>>(() => getInitValue());
const push = (...key: K[]) => {
setArray((prevSet) => {
const temp = Array.from(prevSet);
temp.push(...key);
return temp;
});
};
const unshift = (...key: K[]) => {
setArray((prevSet) => {
const temp = Array.from(prevSet);
temp.unshift(...key);
return temp;
});
};
const pop = () => {
setArray((prevSet) => {
const temp = Array.from(prevSet);
temp.pop();
return temp;
});
};
const shift = () => {
setArray((prevSet) => {
const temp = Array.from(prevSet);
temp.shift();
return temp;
});
};
const reset = () => setArray(getInitValue());
return [
array,
{
push: useMemoizedFn(push),
pop: useMemoizedFn(pop),
shift: useMemoizedFn(shift),
unshift: useMemoizedFn(unshift),
reset: useMemoizedFn(reset),
},
] as const;
}
export default useArray;
簡單使用
const [array,{push,pop,shift,unshift,reset}
] = useArray<string>(['a','b']);//set為['a','b']
push('c','cc')//set為['a','b','c','cc']
pop()//set為['a','b','c']
...