DEV Community

kanta1207
kanta1207

Posted on

We Might Not Need an Effect #1

What this article series are about 🔍

This article series are basically a summary of 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 👎

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

Good 👍

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

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

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.

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

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

Good 👍

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]
  );
}
Enter fullscreen mode Exit fullscreen mode

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

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

Bad 👎

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]);
  // ...
}
Enter fullscreen mode Exit fullscreen mode

Good 👍

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]);
}

Enter fullscreen mode Exit fullscreen mode

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

See you again in #2 !

Top comments (0)