Skip to Content
🎉 Nextra 4.0 is released. dimaMachina is looking for a new job or consulting.
hooksuseArray

useArray

useArray 是一个用于管理数组状态的自定义 Hook,提供了丰富的操作方法(如增、删、改、上下移等),并且在添加元素时会根据指定的唯一键去重,方便管理拥有唯一 ID 或 key 的列表数据。例如,配合 id 字段使用时,添加或合并多个具有相同 id 值的元素会自动去重,避免数据重复。

签名

function useArray<T, K extends keyof T>(initState: T[], key?: K): [ ArrayState<T>, ArrayActions<T, K> ]

泛型参数

  • T:数组元素的类型,如 { id: number; name: string }
  • K:用作判定唯一性的属性键,默认为 'id'(若未显式提供)。

参数

参数类型默认值说明
initStateT[]数组的初始状态。
keyK | undefined'id'用于去重或查找元素的唯一键,若未提供则会被视为 'id'

返回值

Hook 返回一个元组,包含两个部分:

  1. 数组状态T[]
  2. 操作方法ArrayActions<T, K>

数组状态

字段类型说明
[0]T[]数组状态,随操作方法而变化。

操作方法

字段类型说明
clear() => void清空数组,置为 []
down(itemKey: T[K]) => void将指定 itemKey 的元素下移一位。如果元素已在最后一项或找不到,将无操作。
findItem(elementKey: T[K]) => T | undefined根据 elementKey 查找并返回对应元素(若不存在则返回 undefined)。
pop() => void移除并返回数组的最后一个元素(本方法仅移除,不会返回被移除的元素;效果类似 Array.prototype.pop())。
push(...newItems: T[]) => void向数组尾部追加一个或多个元素,并根据唯一键去重。如果新元素与数组中已有元素的 key 相同,则保留最先出现的元素、忽略后续重复项。
remove(itemKey: T[K]) => void根据 itemKey 删除数组中的相应元素。
reset() => void重置数组回到初始状态 initState
reverse() => void反转数组顺序,类似 Array.prototype.reverse()
shift() => void移除并返回数组的第一个元素(本方法仅移除,不会返回被移除的元素;效果类似 Array.prototype.shift())。
sort(compareFn?: (a: T, b: T) => number) => void按照 compareFn 排序数组(若无对比函数则使用默认排序规则),类似 Array.prototype.sort()
splice(start: number, deleteCount?: number, ...items: T[]) => void使用类似 Array.prototype.splice() 的操作,在指定位置插入/删除元素。
unshift(...newItems: T[]) => void向数组头部插入一个或多个元素,且根据唯一键去重(同 push)。
up(itemKey: T[K]) => voiditemKey 对应的元素上移一位。如果元素已在第一项或找不到,将无操作。
updateState(newState: T[] | ((prevState: T[]) => T[])) => void直接更新状态的方法,可传入一个新的数组,或接收前一状态并返回更新后状态的函数。

示例

1. 基础用法

import React from 'react'; import useArray from '@/hooks/useArray'; interface User { id: number; name: string; } export default function Demo() { const [users, actions] = useArray<User, 'id'>([ { id: 1, name: 'Alice' }, { id: 2, name: 'Bob' } ]); const handleAddUser = () => { actions.push({ id: 3, name: 'Charlie' }, { id: 2, name: 'Bob Duplicate' }); }; return ( <div> <ul> {users.map(u => ( <li key={u.id}> {u.id} - {u.name} <button onClick={() => actions.remove(u.id)}>删除</button> </li> ))} </ul> <button onClick={handleAddUser}>添加用户(自动去重)</button> <button onClick={() => actions.up(3)}>将 ID=3 的用户上移</button> <button onClick={() => actions.down(1)}>将 ID=1 的用户下移</button> <button onClick={() => actions.clear()}>清空</button> </div> ); }
  • 点击“添加用户”时会向 users 中追加两个对象:{ id:3, name:'Charlie' }{ id:2, name:'Bob Duplicate' }。由于 id:2 和原有 Bob 重复,所以最终插入的只有一个 id:3
  • “上移/下移”会根据 id 找到对应对象并调整顺序。

2. 自定义键

interface TodoItem { key: string; text: string; } const [todoList, todoActions] = useArray<TodoItem, 'key'>([ { key: 'a', text: 'Do something' }, { key: 'b', text: 'Buy groceries' } ], 'key');

在这里,唯一键从默认的 'id' 改为 'key',内部操作(如 pushremove 等)都以 item.key 做判定,而非 item.id

3. updateState

actions.updateState(prev => { // 在原有数组基础上,增加一个元素 return [...prev, { id: 4, name: 'David' }]; });

当你需要更灵活、更精细化的更新时,可使用 updateState 传入一个函数,该函数接收当前数组状态并返回新的数组状态。等效于 React 中的 setState(prev => newState) 方式。

结论

useArray 为管理数组类型状态提供了一套常用且实用的操作方法,适用于:

  • 需要按照元素中的某个键去重的场景(如 idkey 等)。
  • 增删改查上移下移之类的排序、位置管理。
  • 希望在 React 中使用与原生 Array 类似的操作方法,但又需要更安全、可控的行为。

这样,你可以在组件中轻松编写复杂的列表逻辑,避免重复的数组操作代码,并保持状态管理的简洁与可维护性。

Last updated on