Implement a useArray hook that manages an array of items with additional utility methods.
It is more convenient to use useArray over plain useState because in the latter case, you would always have to create a new array, mutate it, then set state to use the new array, which can be quite cumbersome.
The hook should work generically with arrays of any types.
const defaultValue = ['apple', 'banana'];export default function Component() {const { array, push, update, remove, filter, set, clear } = useArray();return (<div><p>Fruits: {array.join(', ')}</p><button onClick={() => push('orange')}>Add orange</button><button onClick={() => update(1, 'grape')}>Change second item to grape</button><button onClick={() => remove(0)}>Remove first</button><button onClick={() => filter((fruit) => fruit.includes('a'))}>Keep fruits containing 'a'</button><button onClick={() => set(defaultValue)}>Reset</button><button onClick={clear}>Clear list</button></div>);}
defaultValue: The initial array of itemsThe hook returns an object with the following properties:
array: The current array of itemsset: (newArray) => void: A function that sets the array of items. This must be the same type as the setter function of useStatepush: (item) => void: A function that adds an item to the end of the arrayremove: (index: number) => void: A function that removes an item from the array by indexfilter: (predicate) => void: A function that filters the array based on a predicate function. predicate must be the same type as the argument of Array.prototype.filterupdate: (index: number, newItem) => void: A function that replaces an item in the array at indexclear: () => void: A function that clears the arrayThe useArray hook can be implemented by storing the array in a useState state and defining the utility methods to manipulate the array in terms of the state's setter function with JavaScript's built-in array methods.
Remember to wrap the utility methods in useCallback to prevent unnecessary re-renders of the calling component.
import { Dispatch, SetStateAction, useCallback, useState } from 'react';interface UseArrayReturn<T> {array: T[];set: Dispatch<SetStateAction<T[]>>;push: (element: T) => void;filter: (callback: (value: T, index: number, array: T[]) => boolean) => void;update: (index: number, newElement: T) => void;remove: (index: number) => void;clear: () => void;}export default function useArray<T>(defaultValue: T[]): UseArrayReturn<T> {const [array, setArray] = useState(defaultValue);const push: UseArrayReturn<T>['push'] = useCallback((element) => setArray((a) => [...a, element]),[],);const filter: UseArrayReturn<T>['filter'] = useCallback((callback) => setArray((a) => a.filter(callback)),[],);const update: UseArrayReturn<T>['update'] = useCallback((index, newElement) =>setArray((a) => [...a.slice(0, index),newElement,...a.slice(index + 1, a.length),]),[],);const remove: UseArrayReturn<T>['remove'] = useCallback((index) =>setArray((a) => [...a.slice(0, index), ...a.slice(index + 1, a.length)]),[],);const clear: UseArrayReturn<T>['clear'] = useCallback(() => setArray([]), []);return { array, set: setArray, push, filter, update, remove, clear };}
Ensure that the utility methods you implement modify the array in an immutable way since states in React should not be mutated.
console.log() statements will appear here.