@react-hookz/web
Version:
React hooks done right, for browser and SSR.
81 lines (80 loc) • 2.99 kB
JavaScript
import { useMemo, useRef } from 'react';
import { useRerender } from '../useRerender/index.js';
import { useSyncedRef } from '../useSyncedRef/index.js';
import { resolveHookState } from '../util/resolve-hook-state.js';
export function useList(initialList) {
const initial = useSyncedRef(initialList);
const list = useRef(resolveHookState(initial.current));
const rerender = useRerender();
const actions = useMemo(() => ({
set(newList) {
list.current = resolveHookState(newList, list.current);
rerender();
},
push(...items) {
actions.set((currentList) => [...currentList, ...items]);
},
updateAt(index, newItem) {
actions.set((currentList) => {
const listCopy = [...currentList];
listCopy[index] = newItem;
return listCopy;
});
},
insertAt(index, newItem) {
actions.set((currentList) => {
const listCopy = [...currentList];
if (index >= listCopy.length) {
listCopy[index] = newItem;
}
else {
listCopy.splice(index, 0, newItem);
}
return listCopy;
});
},
update(predicate, newItem) {
actions.set((currentList) => currentList.map((item) => (predicate(item, newItem) ? newItem : item)));
},
updateFirst(predicate, newItem) {
const indexOfMatch = list.current.findIndex((item) => predicate(item, newItem));
const NO_MATCH = -1;
if (indexOfMatch > NO_MATCH) {
actions.updateAt(indexOfMatch, newItem);
}
},
upsert(predicate, newItem) {
const indexOfMatch = list.current.findIndex((item) => predicate(item, newItem));
const NO_MATCH = -1;
if (indexOfMatch > NO_MATCH) {
actions.updateAt(indexOfMatch, newItem);
}
else {
actions.push(newItem);
}
},
sort(compareFn) {
actions.set((currentList) => [...currentList].sort(compareFn));
},
filter(callbackFn, thisArg) {
// eslint-disable-next-line unicorn/no-array-callback-reference,unicorn/no-array-method-this-argument
actions.set((currentList) => [...currentList].filter(callbackFn, thisArg));
},
removeAt(index) {
actions.set((currentList) => {
const listCopy = [...currentList];
if (index < listCopy.length) {
listCopy.splice(index, 1);
}
return listCopy;
});
},
clear() {
actions.set([]);
},
reset() {
actions.set([...resolveHookState(initial.current)]);
},
}), [initial, rerender]);
return [list.current, actions];
}