Little React Things: Cleaning up dependencies
Tags: react, javascript, webdev
Published: 2023-01-24 15:17:05

---
title: Little React Things: Cleaning up dependencies
series: Little React Things
published: true
description: We're going to look at a simple way to trim some unnecessary dependencies from our dependency lists.
tags: react, javascript, webdev
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b71wjbz3iqkcncxc27ig.png
# Use a ratio of 100:42 for best results.
canonical_url: https://www.zekehernandez.com/posts/cleaning-up-dependencies
---
*Little React Things is a series of short, React-focused posts where I share some things I've learned over the past few years of developing with React. I hope you find them helpful. These posts might be most helpful for those who have at least a little experience with React already.*

Let's kick this short one off with a little thing you may or may not know, but you definitely should know. The `setState` function identity does not change on rerenders. What this means is that you can (and should) omit `setState`s from the dependency lists of `useEffect` and `useCallback`. This behavior is noted in the [official React docs](https://reactjs.org/docs/hooks-reference.html#usestate).

On to the main topic. For this post I'm gonna roll with the tried and true Todo List example. We have a list of `TodoItem`s and let's say we can have a bunch of them. Since there can be so many of them we wrap each `TodoItem` with `memo` so that each one only rerenders when its own props change.

Furthermore, each todo item can be cloned, so each `TodoItem` has a callback, `onClone`. And we have a little helper function `cloneTodo` that makes such a clone of an existing todo item. The cloned todo is appended to the `todos` state in `handleClone` (if you want to know why I wrapped `handleClone` with `useCallback` take a look at [Your Guide to React.useCallback()](https://dmitripavlutin.com/react-usecallback/)).

Here's our React component:
```jsx
function TodoList() {
    const [todos, setTodos] = useState([])

    const handleClone = useCallback((todo) => {
        setTodos([...todos, cloneTodo(todo)])
    }, [todos])
    
    return (
        <div>
            {todos.map(todo => (
                <TodoItem key={todo.id} todo={todo} onClone={handleClone} />
            ))}
        </div>
    )
}
```

Pretty reasonable right? Ship it! 

***...a few minutes later...***

Uh oh, users have started reporting that their todo lists are really slow, particularly when cloning todo items. What happened? We wrapped our `TodoItem`s with `memo`, so why are they all rendering? Well, one of the props of `TodoItem` is `onClone` and we used `useCallback` for that. And... oh, one of the dependencies of `handleClone` is `todos`. And that `todos` state changes everytime we clone a todo (because we add a new todo to the array). So cloning a todo rerenders *all* the todos. Not great.

Let's make a small change to `handleClone`:
```jsx
const handleClone = useCallback((todo) => {
    setTodos(currentTodos => [...currentTodos, cloneTodo(todo)])
}, [])
```

As I mentioned at the beginning, `setTodos` does not need to be added to the dependency list. So now this new version of `handleClone` doesn't have any dependencies and its identity remains stable throughout the lifetime of the component! Now whenever we clone a todo, that new todo is added to the list without rerendering the already existing ones.

If you want to see these examples live, check them out here:

{% embed https://codesandbox.io/embed/cleaning-up-dependencies-0jcxuc?fontsize=14&hidenavigation=1&theme=dark %}