import type { Reducer } from "react"; import { useReducer } from "react"; export type ListState = { items: T[]; }; type AppendAction = { type: "append"; items: T[]; }; type UpdateAction = { type: "update"; index: number; item: T; }; type DeleteAction<_T> = { type: "delete"; index: number; }; type InsertAfter = { type: "insertAfter"; index: number; items: T[]; }; type Action = AppendAction | UpdateAction | DeleteAction | InsertAfter; function reducer(state: ListState, action: Action): ListState { switch (action.type) { case "append": return { items: [...state.items, ...action.items] }; case "update": return { items: state.items.map((v, i) => (i === action.index ? action.item : v)), }; case "delete": return { items: state.items.filter((_, i) => i !== action.index) }; case "insertAfter": return { items: [ ...state.items.slice(0, action.index + 1), ...action.items, ...state.items.slice(action.index + 1), ], }; } } type HookReturn = { items: T[]; append: (items: T[]) => void; update: (index: number, item: T) => void; delete: (index: number) => void; insertAfter: (index: number, items: T[]) => void; }; export function useList(initialItems: T[]): HookReturn { const [state, dispatch] = useReducer, Action>>(reducer, { items: initialItems, }); return { items: state.items, append: (items: T[]) => dispatch({ type: "append", items }), update: (index: number, item: T) => dispatch({ type: "update", index, item }), delete: (index: number) => dispatch({ type: "delete", index }), insertAfter: (index: number, items: T[]) => dispatch({ type: "insertAfter", index, items }), }; }