Custom React Hooks: useArray
Tags: react, javascript, programming, webdev
Published: 2021-10-31 16:14:00

Another week, another custom React hook for your hooks backpack. In this episode, we'll implement the `useArray` hook to make arrays management easier. Ready? Let's go! 😎

- [Motivation](#motivation)
- [Implementation](#implementation)
- [Usage](#usage)
- [Improvement Ideas](#improvement-ideas)
- [Conclusion](#conclusion)


## Motivation

As usual, let's first discover how this hook could be useful to you. Let's be original and creative: suppose you are building a To-Do list application with React. At some point, you'll have to manage the user's tasks: to do so, you'll use an array, along with the `useState` hook. The `addTask` function might look like this:

```jsx
const addTask = (newTask) => {
  setTasks(oldTasks => [...oldTasks, newTasks])
}
```

Then, you'd have a `removeTask` function, that could look like this:

```jsx
const removeTask = (index) => {
  setTasks(oldTasks => oldTasks.filter((_, i) => i !== index))
}
```

As you can see, this can quickly become a bit hard to read.

This is why we will create the `useArray` hook to simplify our code.


## Implementation

First, let's create the hook's base structure.

```jsx
const useArray = (initialValue = []) => {
  const [value, setValue] = useState(initialValue)

  return { value, setValue }
}
```

Then we'll add the `push` function to add an element at the end of the array.

```jsx
const push = element => {
  setValue(oldValue => [...oldValue, element]);
};
```

Let's also create the `remove` function to remove an element at a given index.

```jsx
const remove = index => {
  setValue(oldValue => oldValue.filter((_, i) => i !== index));
};
```

It can also be handy to add an `isEmpty` function to check for the array emptiness.

```jsx
  const isEmpty = () => value.length === 0;
```

Combining all these functions together, here's how the final hook will look like:

```jsx
const useArray = (initialValue = []) => {
  const [value, setValue] = useState(initialValue);

  const push = element => {
    setValue(oldValue => [...oldValue, element]);
  };

  const remove = index => {
    setValue(oldValue => oldValue.filter((_, i) => i !== index));
  };

  const isEmpty = () => value.length === 0;

  return { value, setValue, push, remove, isEmpty };
};
```

If you are working with large amount of data, feel free to optimize this hook by using `useCallback` (more info [here](https://dmitripavlutin.com/dont-overuse-react-usecallback/)).

> Example:
> ```jsx
> const push = useCallback(element => {
>   setValue(oldValue => [...oldValue, element])
> }, [])
> ```

Also, if you need other array methods such as `map` or `unshift`, don't  hesitate to adapt it to your needs (you can even add custom functions).

## Usage

Back to our To-Do list example. By using our brand new hook, this is how the component could now look like:

```jsx
const TodoList = () => {
  const tasks = useArray([]);
  const [newTask, setNewTask] = useState("");

  // "Add" button clicked
  const handleSubmit = e => {
    e.preventDefault();
    tasks.push(newTask);
    setNewTask("");
  };

  const handleInputChange = e => setNewTask(e.target.value);

  return (
    <>
      <h1>Todo List</h1>
      <form onSubmit={handleSubmit}>
        <input type="text" value={newTask} onChange={handleInputChange} />
        <button>Add</button>
      </form>
      {tasks.isEmpty() ? (
        <p>No tasks to display</p>
      ) : (
        <ul>
          {tasks.value.map((task, index) => (
            <li key={index}>
              <input
                type="checkbox"
                onClick={() => tasks.remove(index)}
                checked={false}
              />
              {task}
            </li>
          ))}
        </ul>
      )}
    </>
  );
};
```

Notice that we don't even need the `addTask` and `removeTask` functions anymore, as our `tasks.push` and `tasks.remove` ones are already explicit and easy to read.

## Improvement Ideas

To go further, here are some ideas of improvements to enhance this hook.

- Adding a `reverse` function to reverse the array
- Adding a `sort` function to sort the array
- Adding a `clear` function to clear the array

## Conclusion

I hope this hook will be useful to you for your future (or existing) projects. If you have any questions, feel free to ask them in the comments section.

Thanks for reading me, and see you next time for a new custom hook. 🤗

---

**Source code** available on [CodeSandbox](https://codesandbox.io/s/custom-react-hooks-usearray-fi13z?file=/src/App.js).

{% codesandbox custom-react-hooks-usearray-fi13z %}

---

## Support Me

If you wish to support me, you can buy me a coffee with the following link (I will then probably turn that coffee into a new custom hook... ☕)

[![Buy Me A Coffee](https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png)](https://www.buymeacoffee.com/iamludal)