🧠 Introduction to useEffect and Next.js

If you're learning React and jump into Next.js, you might quickly notice something frustrating: useEffect doesn’t behave the way you expect.

Understanding why useEffect breaks in Next.js — and how to fix it is super important if you want to build modern apps without bugs.

Let’s break it down in the simplest way possible 👇


🔍 What is useEffect in React

useEffect is a React Hook that runs code after the component renders.

👉 Common uses:

  • Fetching data

  • Accessing browser APIs (like window)

  • Setting timers

Example:

useEffect(() => {
  console.log("Component mounted");
}, []);

⚡ What makes Next.js different from React

Here’s the key difference:

React

Next.js

Runs in browser

Runs on server + browser

Client-side rendering

Server-side rendering (SSR)

👉 This is where problems start!


🚨 Why useEffect breaks in Next.js

🖥️ Server-Side Rendering (SSR) vs Client-Side Rendering

Next.js first renders your page on the server, then sends it to the browser.

But...

👉 useEffect ONLY runs in the browser (client-side).


❗ useEffect runs only on the client

That means:

  • It does NOT run during server rendering

  • It runs AFTER hydration (when React takes over)


⚠️ Hydration mismatch issues

Sometimes:

  • Server output ≠ Client output

This causes errors like:

Hydration failed because the initial UI does not match

😵 Common Problems Developers Face

1. useEffect not running

Because you're expecting it to run on the server — but it doesn't.


2. "window is not defined" error

This is the MOST common error.

Why?

👉 Because window exists only in the browser, not on the server.


3. Infinite loops in useEffect

Bad dependency arrays can cause:

useEffect(() => {
  setState(value);
});

👉 This runs forever 😬


💡 Real Example: useEffect Breaking in Next.js

❌ Problem Code

import { useEffect } from "react";

export default function Page() {
  useEffect(() => {
    console.log(window.innerWidth);
  }, []);

  return <div>Hello</div>;
}

💥 Why it fails

  • Next.js tries to render this on the server

  • window does NOT exist there

  • Result: crash or error


🛠️ Step-by-Step Fixes

✅ Fix 1: Use "use client" directive

In Next.js (App Router):

"use client";

import { useEffect } from "react";

export default function Page() {
  useEffect(() => {
    console.log("Runs only on client");
  }, []);

  return <div>Hello</div>;
}

👉 This ensures the component runs only in the browser.


✅ Fix 2: Check for window safely

useEffect(() => {
  if (typeof window !== "undefined") {
    console.log(window.innerWidth);
  }
}, []);

👉 Prevents server crash.


✅ Fix 3: Use dynamic import with SSR disabled

import dynamic from "next/dynamic";

const NoSSRComponent = dynamic(() => import("./MyComponent"), {
  ssr: false,
});

👉 This completely skips server rendering.


✅ Fix 4: Fix dependency array issues

Bad:

useEffect(() => {
  setCount(count + 1);
});

Good:

useEffect(() => {
  setCount(count + 1);
}, []);

👉 Always define dependencies properly.


📌 Best Practices for useEffect in Next.js

✔️ Keep logic client-side only

Only use useEffect for:


  • Browser APIs


  • DOM updates


✔️ Avoid heavy logic in useEffect

Don’t:

  • Fetch large data unnecessarily

  • Run expensive calculations


✔️ Use proper dependency arrays

Always ask:

👉 "When should this run?"


🚀 Advanced Tips

useLayoutEffect vs useEffect

  • useEffect → runs after paint

  • useLayoutEffect → runs before paint

⚠️ In Next.js:

  • Avoid useLayoutEffect on server


Handling API calls properly

Better approach in Next.js:

👉 Use server-side data fetching:

  • fetch() in Server Components

  • getServerSideProps (older)


❓ FAQs

1. Why does useEffect not run on server?

Because it is designed to run only in the browser after rendering.


2. What causes "window is not defined"?

Using browser APIs during server rendering.


3. How to fix hydration errors?

Ensure server and client output match, or use client-only components.

4. Should I always use "use client"?

No. Only when you need client-side features like hooks.

5. Is useEffect bad in Next.js?

Not at all — just use it correctly.

6. What is the safest way to use useEffect?

Use it only for browser-related logic and guard with checks.


🏁 Conclusion

Now you clearly understand why useEffect breaks in Next.js — and how to fix it.

👉 The main issue is simple:

  • Next.js runs on the server

  • useEffect runs on the client

Once you understand this difference, everything becomes much easier.

💡 Just remember:

  • Use "use client" when needed

  • Avoid server-only errors

  • Write clean and safe useEffect logic