1

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']
...

Non_
1 声望0 粉丝