- Published on
- -⏳5 mins read
Mastering Array Manipulation in React with useArray Hook
- Authors
- Name
- Seraj Vahdati
- @seraj
Introduction
Working with arrays in React can often become complex, especially when managing stateful arrays with frequent operations like adding, removing, or filtering elements. The useArray
custom hook simplifies these operations and, when combined with TypeScript, provides strong type safety and better developer experience. In this post, we'll explore how to use useArray
with TypeScript to streamline your React application development.
useArray
?
Why Use TypeScript with TypeScript brings static typing to JavaScript, which helps catch errors early in the development process. By using TypeScript with useArray
, you gain several benefits, including:
- Type Safety: Ensures that array operations are performed on the correct data types.
- Better IntelliSense: Provides auto-completion and inline documentation in your IDE.
- Reduced Bugs: Catch potential issues during compile time rather than at runtime.
useArray
in TypeScript
Setting Up First, import the useArray
hook into your component:
import { useState } from 'react'
type UseArrayReturnType<T> = { array: T[] set: React.Dispatch<React.SetStateAction<T[]>> push: (element: T) => void filter: (callback: (element: T, index: number, array: T[]) => boolean) => void update: (index: number, newElement: T) => void remove: (index: number) => void clear: () => void pop: () => void find: (callback: (element: T, index: number, array: T[]) => boolean) => T | undefined findIndex: (callback: (element: T, index: number, array: T[]) => boolean) => number includes: (element: T) => boolean isEmpty: () => boolean}
const useArray = <T>(initialValue: T[] = []): UseArrayReturnType<T> => { const [array, setArray] = useState<T[]>(initialValue)
const push = (element: T) => setArray((a) => [...a, element])
const filter = (callback: (element: T, index: number, array: T[]) => boolean) => setArray((a) => a.filter(callback))
const update = (index: number, newElement: T) => { setArray((a) => index >= 0 && index < a.length ? [...a.slice(0, index), newElement, ...a.slice(index + 1)] : a ) }
const remove = (index: number) => { setArray((a) => index >= 0 && index < a.length ? [...a.slice(0, index), ...a.slice(index + 1)] : a ) }
const clear = () => setArray([])
const pop = () => { setArray((a) => a.slice(0, a.length - 1)) }
const find = (callback: (element: T, index: number, array: T[]) => boolean) => array.find(callback)
const findIndex = (callback: (element: T, index: number, array: T[]) => boolean) => array.findIndex(callback)
const includes = (element: T) => array.includes(element)
const isEmpty = () => array.length === 0
return { array, set: setArray, push, filter, update, remove, clear, pop, find, findIndex, includes, isEmpty, }}
export default useArray
import useArray from './useArray'
Initialize the hook with a default array:
const MyComponent = () => { const { array, push, update, remove, clear, pop, find, findIndex, includes, isEmpty, } = useArray<number>([1, 2, 3])
// Your component logic here}
useArray
Key Methods in -
push(element: T)
: Adds a new element to the array.push(4) // array: [1, 2, 3, 4] -
update(index: number, newElement: T)
: Updates an element at a specified index.update(1, 10) // array: [1, 10, 3] -
remove(index: number)
: Removes the element at the specified index.remove(0) // array: [2, 3] -
filter(callback: (element: T, index: number, array: T[]) => boolean)
: Filters the array based on a callback function.filter((num) => num > 1) // array: [2, 3] -
clear()
: Clears the entire array.clear() // array: [] -
pop()
: Removes the last element from the array.pop() // array: [1, 2] -
find(callback: (element: T, index: number, array: T[]) => boolean): T | undefined
: Finds the first element that matches the condition in the callback.const found = find((num) => num > 1) // found: 2 -
findIndex(callback: (element: T, index: number, array: T[]) => boolean): number
: Finds the index of the first element that matches the condition in the callback.const index = findIndex((num) => num > 1) // index: 1 -
includes(element: T): boolean
: Checks if the array includes a specific element.const isInArray = includes(2) // isInArray: true -
isEmpty(): boolean
: Checks if the array is empty.const empty = isEmpty() // empty: false
Example Use Case
Consider a situation where you're building a todo list. You can use useArray
to manage the list of tasks:
type Todo = { id: number; text: string; completed: boolean }
const TodoList = () => { const { array: todos, push, update, remove, clear } = useArray<Todo>([])
const addTodo = (text: string) => { push({ id: Date.now(), text, completed: false }) }
const toggleTodo = (id: number) => { const index = todos.findIndex((todo) => todo.id === id) if (index !== -1) { update(index, { ...todos[index], completed: !todos[index].completed }) } }
const deleteTodo = (id: number) => { const index = todos.findIndex((todo) => todo.id === id) if (index !== -1) { remove(index) } }
return ( <div> <button onClick={() => addTodo('New Task')}>Add Task</button> <ul> {todos.map((todo) => ( <li key={todo.id}> <span style={{ textDecoration: todo.completed ? 'line-through' : 'none' }} onClick={() => toggleTodo(todo.id)} > {todo.text} </span> <button onClick={() => deleteTodo(todo.id)}>Delete</button> </li> ))} </ul> <button onClick={clear}>Clear All</button> </div> )}
Conclusion
Using useArray
with TypeScript is a powerful way to manage arrays in your React applications. The added type safety, along with the intuitive array manipulation methods, allows you to write cleaner, more maintainable code. By adopting useArray
in your projects, you can reduce bugs, improve code readability, and boost your productivity.
Happy coding with TypeScript and React!