Magento 2 Experten — Hyvä Theme, Tailwind CSS & SEO aus einer Hand ›

Understanding useEffect: Side Effects in React (Tutorial)

Understanding useEffect

~11 Min. Lesezeit Zuletzt aktualisiert am August 8, 2026

Welcome to Phase 2: we now dive deep into the most important hooks – functions that let components "hook into" React functionality like state (hence the name "hook"). You already know the first one, useState. Now comes useEffect – one of the most important, but also most misunderstood, hooks.

What is a "side effect"?

Rendering a component (running the function and returning JSX) should always be a "pure" affair: same props/state in, same JSX out, no side effects on the outside world. But some things can't be expressed that way: loading data from a server, changing the browser tab title, starting a timer, listening for a browser event. These are side effects – things that happen outside of pure rendering. That's what useEffect is for.

useEffect() basics

import { useEffect } from 'react';

function Example() {
  useEffect(() => {
    console.log('The component was rendered (or re-rendered)');
  });

  return <p>Hello</p>;
}

Without a second argument, the effect function runs after EVERY render – usually not what you want. The second argument, the "dependency array", controls exactly WHEN the effect should run again:

CallWhen the effect runs
useEffect(fn) – no second argumentruns after EVERY render (rarely useful)
useEffect(fn, []) – empty arrayruns only ONCE, right after the first render
useEffect(fn, [value]) – array with valuesruns again whenever one of the listed values changes

Practical example: keeping the browser tab title in sync

A classic, real side effect: the browser tab title lives outside the React-controlled <div id="root"> and must be set via the browser API document.title. Extend src/App.jsx:

src/App.jsx
import { useEffect } from 'react';
import ProductCard from './components/ProductCard';

const SAMPLE_PRODUCTS = [
  { sku: 'boots-01', name: 'Hiking Boots', price: 89.99, imageUrl: 'https://picsum.photos/seed/1/300' },
  { sku: 'backpack-01', name: 'Trekking Backpack', price: 59.5, imageUrl: 'https://picsum.photos/seed/2/300' },
  { sku: 'jacket-01', name: 'Rain Jacket', price: 74.0, imageUrl: 'https://picsum.photos/seed/3/300' },
];

function App() {
  useEffect(() => {
    document.title = `Product Catalog (${SAMPLE_PRODUCTS.length} products)`;
  }, []);

  return (
    <div className="app">
      <h1>Product Catalog</h1>
      <div className="product-grid">
        {SAMPLE_PRODUCTS.map((product) => (
          <ProductCard
            key={product.sku}
            name={product.name}
            price={product.price}
            imageUrl={product.imageUrl}
            onSelect={() => alert(product.name + ' tapped')}
          />
        ))}
      </div>
    </div>
  );
}

export default App;

Save and look at the browser tab: "Product Catalog (3 products)". The empty array [] makes sure this code runs only ONCE, right after the component is first displayed – comparable to the DOMContentLoaded event.

The cleanup function

Some effects need to be "cleaned up" when the component disappears or the effect runs again – e.g. a timer that would otherwise keep running even though the component is long gone. For this, the effect function itself can return a function:

useEffect(() => {
  const timerId = setInterval(() => {
    console.log('Tick');
  }, 1000);

  return () => {
    clearInterval(timerId); // runs before the effect re-runs OR the component disappears
  };
}, []);

Achtung: The most common useEffect mistake for beginners: forgetting the dependency array or filling it incorrectly. If a value the effect function actually uses is missing, the "react-hooks/exhaustive-deps" ESLint rule (pre-installed in every Vite React project) warns in your editor – take that warning seriously, it almost always points to a real bug (the effect then "sees" stale values).