Understanding useEffect in React (and Next.js) – A Beginner’s Guide

Wayne
By Wayne ·

If you’re just starting out with React or Next.js, one of the first Hooks you’ll encounter is useEffect. At first, it may look a bit mysterious, but don’t worry — this guide will break it down step by step in plain English.

What is useEffect?

In React, useEffect is a Hook used to handle side effects in your components.

A side effect means anything that happens outside the normal process of rendering UI. For example:

  • Fetching data from an API
  • Listening to user events (like scrolling or resizing the window)
  • Starting or cleaning up timers
  • Interacting with localStorage or other browser APIs

In short: useEffect lets you run code after your component renders.

Basic Example

import { useEffect, useState } from "react";

export default function MyComponent() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    console.log("Component rendered!");
  });

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  );
}

What happens here?

  • The first time the component appears, the message "Component rendered!" is logged.
  • Every time count changes, the component re-renders — and the effect runs again.

The Dependency Array

useEffect takes a second argument: the dependency array. This controls when the effect should run.

useEffect(() => {
  console.log("Runs only when `count` changes");
}, [count]);
  • [] → Runs only once (on mount). Useful for initialization.
  • [count] → Runs when count changes.
  • (no array) → Runs after every render (not recommended unless you really need it).

Cleaning Up Effects

Some effects need cleanup, like event listeners or timers. You can return a function inside useEffect to clean things up.

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

  // Cleanup when component unmounts or before running again
  return () => {
    clearInterval(timer);
    console.log("Timer cleared!");
  };
}, []);

Special Notes for Next.js

Because Next.js does server-side rendering (SSR), it’s important to know:

  • useEffect only runs on the client-side, never on the server.
  • That means you can safely use browser-only features (like window or localStorage) inside useEffect.

Key Takeaways

  • useEffect = run side effects after render.
  • The dependency array controls when it runs.
  • Return a function to clean up things like timers or event listeners.
  • In Next.js, it only runs in the browser, not on the server.