UNPKG

@react-hookz/web

Version:

React hooks done right, for browser and SSR.

81 lines (80 loc) 3.27 kB
import { useMemo, useRef } from 'react'; import { resolveHookState } from "../util/resolveHookState.js"; import { useRerender, useSyncedRef } from '..'; 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) => { /* We're implementing filter based on the Array.prototype.filter API, thus the API is not going to change, and we can turn off the no-array-callback-reference rule. Also, the filter API requires the thisArg, so we can turn off the no-array-method-this-argument-rule. */ // 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]; }