130 lines
2.4 KiB
TypeScript
130 lines
2.4 KiB
TypeScript
import { useReducer } from 'preact/hooks'
|
|
|
|
type DefaultItem = {
|
|
id: number
|
|
}
|
|
|
|
const ADD = 'add'
|
|
|
|
type AddAction<I> = {
|
|
type: typeof ADD
|
|
payload: I
|
|
}
|
|
|
|
const add = <I>(item: I): AddAction<I> => ({
|
|
type: ADD,
|
|
payload: item,
|
|
})
|
|
|
|
const DEL = 'delete'
|
|
|
|
type DeleteAction = {
|
|
type: typeof DEL
|
|
id: number
|
|
}
|
|
|
|
const del = (id: number): DeleteAction => ({
|
|
type: DEL,
|
|
id,
|
|
})
|
|
|
|
const LOAD = 'load'
|
|
|
|
type LoadAction<I> = {
|
|
type: typeof LOAD
|
|
payload: I[]
|
|
}
|
|
|
|
const load = <I>(items: I[]): LoadAction<I> => ({
|
|
type: LOAD,
|
|
payload: items,
|
|
})
|
|
|
|
const RESET = 'reset'
|
|
|
|
type ResetAction<I> = {
|
|
type: typeof RESET
|
|
payload: I[]
|
|
}
|
|
|
|
const reset = <I>(items: I[] = []): ResetAction<I> => ({
|
|
type: RESET,
|
|
payload: items,
|
|
})
|
|
|
|
const UPDATE = 'update'
|
|
|
|
type UpdateAction<I> = {
|
|
type: typeof UPDATE
|
|
id: number
|
|
payload: I
|
|
}
|
|
|
|
const update = <I>(id: number, item: I): UpdateAction<I> => ({
|
|
type: UPDATE,
|
|
id,
|
|
payload: item,
|
|
})
|
|
|
|
export const actions = {
|
|
add,
|
|
del,
|
|
load,
|
|
reset,
|
|
update,
|
|
}
|
|
|
|
type Action<I> = AddAction<I> | DeleteAction | LoadAction<I> | ResetAction<I> | UpdateAction<I>
|
|
|
|
export const itemsReducer = <I extends DefaultItem>(state: I[], action: Action<I>) => {
|
|
switch (action.type) {
|
|
case ADD:
|
|
return [...state, action.payload]
|
|
case DEL: {
|
|
const index = state.findIndex((item) => item.id === action.id)
|
|
|
|
if (index > -1) {
|
|
return [...state.slice(0, index), ...state.slice(index + 1)]
|
|
}
|
|
|
|
return state
|
|
}
|
|
case LOAD: {
|
|
return [...state, ...action.payload]
|
|
}
|
|
case RESET: {
|
|
return [...action.payload]
|
|
}
|
|
case UPDATE: {
|
|
const index = state.findIndex((item) => item.id === action.id)
|
|
|
|
if (index > -1) {
|
|
const newItem = {
|
|
...state[index],
|
|
...action.payload,
|
|
}
|
|
|
|
return [...state.slice(0, index), newItem, ...state.slice(index + 1)]
|
|
}
|
|
|
|
return state
|
|
}
|
|
default:
|
|
return state
|
|
}
|
|
}
|
|
|
|
export default <I extends DefaultItem>(init: I[] = []) => {
|
|
const [items, dispatch] = useReducer(itemsReducer<I>, init)
|
|
|
|
const actions = {
|
|
add: (item: I) => dispatch(add<I>(item)),
|
|
del: (id: number) => dispatch(del(id)),
|
|
load: (items: I[]) => dispatch(load<I>(items)),
|
|
reset: (items: I[]) => dispatch(reset<I>(items)),
|
|
update: (id: number, item: I) => dispatch(update<I>(id, item)),
|
|
}
|
|
|
|
return [items, actions] as [I[], typeof actions]
|
|
}
|