useArray

数组状态 hook,返回 [state, store],store 上带 14 个按 key 语义的数组操作

function useArray<T, K extends keyof T>(initState: T[], key?: K): [T[], ArrayStore<T, K>];
参数类型默认说明
initStateT[]初始数组,同时作为 reset() 的目标
keyK extends keyof T'id'用于唯一标识元素的字段名

返回 [当前数组, ArrayStore 实例]。操作方法都挂在 store 上,不在返回值第一项里。

import { useArray } from '@skyroc/hooks';

interface Todo {
  id: string;
  title: string;
}

const TodoList = () => {
  const [todos, store] = useArray<Todo, 'id'>([]);

  return (
    <>
      {todos.map(todo => (
        <div key={todo.id}>
          {todo.title}
          <button
            type="button"
            onClick={() => store.remove(todo.id)}
          >
            删除
          </button>
          <button
            type="button"
            onClick={() => store.up(todo.id)}
          >
            上移
          </button>
        </div>
      ))}
      <button
        type="button"
        onClick={() => store.push({ id: crypto.randomUUID(), title: '新任务' })}
      >
        新增
      </button>
    </>
  );
};

ArrayStore 方法

增删

方法签名说明
push(...items: T[]) => void尾部追加,按 key 去重
unshift(...items: T[]) => void头部追加,按 key 去重
remove(itemKey: T[K]) => void按 key 移除
pop() => void移除末尾
shift() => void移除首部
splice(start: number, deleteCount?: number, ...items: T[]) => void按下标增删
clear() => void清空
reset() => void恢复到 initState

push / unshift 的去重是保留先出现的那个:合并后按 key 做 findIndex 过滤,所以重复 key 的新元素会被丢弃,而不是覆盖旧元素。

排序

方法签名说明
up(itemKey: T[K]) => void与前一个元素交换;已是首个则不动
down(itemKey: T[K]) => void与后一个元素交换;已是末个或不存在则不动
reverse() => void反转(toReversed,不改原数组)
sort(compareFn?: (a: T, b: T) => number) => void排序(toSorted,不改原数组)

读取与整体替换

方法签名说明
findItem(elementKey: T[K]) => T | undefined按 key 查找,直接读 class 内部状态,不受 React 渲染周期影响
updateState(next: T[] | ((prev: T[]) => T[])) => void整体替换

findItem 读的是 store 当前值而非本次渲染闭包里的 todos,所以在事件回调里连续操作时拿到的一定是最新数据。

为什么方法在 store 上而不在返回值里

ArrayStore 继承 Store<T[]>,所有方法都是 class 的箭头函数属性,引用在组件整个生命周期内稳定,直接传给子组件或放进依赖数组都不会触发额外渲染,不需要 useCallback 包一层。

store 由 useCreation(() => new ArrayStore(initState, key), []) 创建,依赖数组为空——initStatekey 只在首次渲染生效,后续变化不会重建 store。要换数据源用 updateState

Last updated on