We Might Not Need an Effect #1
Published: 2024-05-06 18:53:15

## What this article series are about 🔍

This article series are basically a summary of [You Might Not Need an Effect](https://react.dev/learn/you-might-not-need-an-effect), which is a React official documentation about the usage of `useEffect` hook in React.

**The original article is really really good, for sure better than my summary.** So, if you have time, I highly recommend you to read the original article.

My motivation is just to provide a quick summary both for myself and for others who might be busy or a bit lazy to read through the whole article.

Yeah, it's for you 😉 haha

I summarized the content as short as possible, so we can get main idea quickly.
So don't forget to check the original article for more detailed information. Again, it's really good learning material.

## When something can be calculated from the existing props or state, we don't need extra state and useEffect

### Bad 👎

```tsx
function Form() {
  const [firstName, setFirstName] = useState('');
  const [lastName, setLastName] = useState('');

  // 🔴  Unnecessary extra state and useEffect
  const [fullName, setFullName] = useState('');
  useEffect(() => {
    setFullName(firstName + ' ' + lastName);
  }, [firstName, lastName]);
  //

  return (
    <div>
      <input
        value={firstName}
        onChange={(e) => setFirstName(e.target.value)}
        placeholder="First Name"
      />
      <input
        value={lastName}
        onChange={(e) => setLastName(e.target.value)}
        placeholder="Last Name"
      />
      <h1>{fullName}</h1>
    </div>
  );
}
```

### Good 👍

```tsx
function Form() {
  const [firstName, setFirstName] = useState('');
  const [lastName, setLastName] = useState('');

  // ✅  No extra state and useEffect
  const fullName = firstName + ' ' + lastName;

  return (
    <div>
      <input
        value={firstName}
        onChange={(e) => setFirstName(e.target.value)}
        placeholder="First Name"
      />
      <input
        value={lastName}
        onChange={(e) => setLastName(e.target.value)}
        placeholder="Last Name"
      />
      <h1>fullName</h1>
    </div>
  );
}
```

### Takeaway

**The point is to let re-render do the calculation**, instead of doing it with extra state and `useEffect`.
When we call setFirstName or setLastName, we trigger a re-render, and then the next fullName will be calculated from the fresh data.

### Reference

- [Updating state based on props or state](https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state)
- [Avoid redundant state](https://react.dev/learn/choosing-the-state-structure#avoid-redundant-state)

## When we use `useEffect` just to update something only when some props or state is updated, what we really need is `useMemo`.

### Bad 👎

`getFilteredTodos` is a function that filters todos based on the filter, and it is used to calculate `visibleTodos`.
Maybe you want to update `visibleTodos` only when `todos` or `filter` changes.

```tsx
function TodoList({ todos, filter }) {
  const [newTodo, setNewTodo] = useState('');

  // 🔴  Unnecessary extra state and useEffect
  const [visibleTodos, setVisibleTodos] = useState([]);
  useEffect(() => {
    setVisibleTodos(getFilteredTodos(todos, filter));
  }, [todos, filter]);
 ...
}
```

### Good 👍

```tsx
function TodoList({ todos, filter }) {
  const [newTodo, setNewTodo] = useState('');

  // ✅  No extra state and useEffect, but efficient use of useMemo
  const visibleTodos = useMemo(
    () => getFilteredTodos(todos, filter),
    [todos, filter]
  );
}
```

### Takeaway

If your motivation to use `useEffect` is just to update something only when some props or state is updated, what you really need is `useMemo`.

### Reference

- [Caching expensive calculation](https://react.dev/learn/you-might-not-need-an-effect#caching-expensive-calculations)

## When we want to reset the state based on some prop change, we could do it witout `useEffect`

### Bad 👎

```tsx
function List({ items }) {
  const [isReverse, setIsReverse] = useState(false);
  const [selectedItem, setSelectedItem] = useState(null);

  // 🔴 Avoid: resetting state on prop change in an Effect
  useEffect(() => {
    setSelection(null);
  }, [items]);
  // ...
}
```

### Good 👍

```tsx
function List({ items }) {
  const [isReverse, setIsReverse] = useState(false);
//   Change selectedItem to selectedItemId, so that we don't need to reset state on prop change
  const [selectedItemId, setSelectedItemId] = useState(null);

  // ✅  No extra state and useEffect, just calculate selectedItem when selectedItemId changes
  const selectedItem = useMemo(items.find((item) => item.id === selectedItemId);,[items, selectedItemId]);
}

```

### Takeaway

When you adjusting or resetting the state based on some prop change, you better to think about the way to do it without `useEffect`

### Reference

- [Adjusting some state when a prop changes](https://react.dev/learn/you-might-not-need-an-effect#adjusting-some-state-when-a-prop-changes)

## See you again in #2 !