乐趣区

关于typescript:④reactahooks源码分析之useSet

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']
...
退出移动版