← Back to all posts

You Might Not Need an Effect

Effects (useEffect) are React's escape hatch for synchronizing with external systems. But most of the time, you don't need them. Removing unnecessary Effects makes code faster, simpler, and less error-prone.

Based on React Documentation: You Might Not Need an Effect


Transform Data During Rendering

Don't use Effects to transform data for display. Calculate it during render instead.

❌ Bad:

function Form() {
  const [firstName, setFirstName] = useState('Taylor');
  const [lastName, setLastName] = useState('Swift');
  const [fullName, setFullName] = useState('');

  useEffect(() => {
    setFullName(firstName + ' ' + lastName);
  }, [firstName, lastName]);
}

✅ Good:

function Form() {
  const [firstName, setFirstName] = useState('Taylor');
  const [lastName, setLastName] = useState('Swift');
  const fullName = firstName + ' ' + lastName;
}

Why? Extra state causes unnecessary re-renders and cascading updates.


Cache Expensive Calculations

Wrap slow computations in useMemo to skip unnecessary recalculations.

function TodoList({ todos, filter }) {
  const visibleTodos = useMemo(() => {
    return getFilteredTodos(todos, filter);
  }, [todos, filter]);
}

Only recalculates when todos or filter actually changes.


Handle User Events in Handlers

User actions belong in event handlers, not Effects.

❌ Bad:

useEffect(() => {
  showNotification('Item added!');
}, [product]);

✅ Good:

function handleBuyClick() {
  addToCart(product);
  showNotification('Item added!');
}

Why? Effects don't know what happened—only that something changed.


Reset State with Keys

Use key prop to reset component state when navigating.

function ProfileList({ profiles }) {
  return profiles.map(profile => (
    <Profile key={profile.id} userId={profile.id} />
  ));
}

When key changes, React automatically resets that component's state.


Fetch Data Safely

Always add cleanup to fetch Effects to avoid race conditions.

useEffect(() => {
  let ignore = false;

  fetch(`/api/search?q=${query}`)
    .then(res => res.json())
    .then(data => {
      if (!ignore) {
        setResults(data);
      }
    });

  return () => { ignore = true; };
}, [query]);

Why? Prevents showing stale results when typing fast or navigating quickly.


Key Takeaways

Use Effect For Use Instead
Transform data Calculate during render
User events Event handlers
Expensive calcs useMemo
Reset on navigation key prop
App init once Top-level module or root App
External sync useSyncExternalStore
Parent communication Pass data down (lift state up)
Fetch data Add cleanup function

Remember

Effects sync with external systems—network, browser APIs, third-party libraries. If it's about your own app's data, you probably don't need an Effect.