staff_data/packages/client/src/hooks/useStack.ts

129 lines
3.5 KiB
TypeScript
Raw Normal View History

2024-12-30 08:26:40 +08:00
/**
* useStack
* React的栈StackHook
*
* 1.0.0
* 使React组件中管理栈结构数据的场景/
*/
import { Dispatch, SetStateAction, useMemo, useState } from "react";
/**
* StackHook<T>
* Hook的返回对象结构
*
*/
export interface StackHook<T> {
stack: T[]; // 当前栈中的元素数组
push: (item: T) => void; // 将元素压入栈顶
pop: () => void; // 弹出栈顶元素
popToItem: (item: T) => void; // 弹出栈中元素直到指定元素
peek: () => T | undefined; // 查看栈顶元素
isEmpty: boolean; // 判断栈是否为空
clear: () => void; // 清空栈
isOnlyDefaultItem: boolean; // 判断栈中是否仅包含默认元素
setStack: Dispatch<SetStateAction<T[]>> // 直接设置栈内容
}
/**
* useStack<T>
* Hook实例
*
* React的Hook模式
* 使
* const { stack, push, pop } = useStack<number>();
* push(1); // 栈:[1]
* push(2); // 栈:[1, 2]
* pop(); // 栈:[1]
*/
export function useStack<T>(defaultBottomItem?: T | null): StackHook<T> {
// 初始化栈状态,支持设置默认底部元素
const [stack, setStack] = useState<T[]>(
!!defaultBottomItem ? [defaultBottomItem] : []
);
/**
* push
*
* item -
* O(1)
*/
const push = (item: T) => setStack((prevStack) => [...prevStack, item]);
/**
* pop
*
* O(1)
*/
const pop = () =>
setStack((prevStack) =>
prevStack.length > 0 ? prevStack.slice(0, -1) : prevStack
);
/**
* popToItem
*
* item -
* O(n)n为栈中元素数量
*/
const popToItem = (item: T) => {
setStack((prevStack) => {
const index = prevStack.lastIndexOf(item);
return index >= 0 && index < prevStack.length - 1
? prevStack.slice(0, index + 1)
: prevStack;
});
};
/**
* peek
*
* undefined
* O(1)
*/
const peek = (): T | undefined => stack[stack.length - 1];
/**
* isEmpty
*
* booleantrue表示栈为空
* O(1)
*/
const isEmpty = useMemo(() => {
return stack.length === 0;
}, [stack, defaultBottomItem]);
/**
* isOnlyDefaultItem
*
* booleantrue表示栈中仅包含默认元素
* O(1)
*/
const isOnlyDefaultItem = useMemo(() => {
if (defaultBottomItem !== undefined) {
return stack.length === 1 && stack[0] === defaultBottomItem;
}
return stack.length === 0;
}, [stack, defaultBottomItem]);
/**
* clear
*
* O(1)
*/
const clear = () =>
setStack(!!defaultBottomItem ? [defaultBottomItem] : []);
return {
stack,
setStack,
push,
pop,
popToItem,
peek,
isEmpty,
clear,
isOnlyDefaultItem,
};
}