Using Browser APIs

TopicSource
ReactAll 29 Next.js Mistakes Beginners Make - YouTube

In Next.js, if you are using browser APIs in client components, you need to ensure that the code runs only on the client side. This is important because browser APIs like window, document, or localStorage are not available during server-side rendering (SSR). Here's how you can safely use browser APIs in client components:


1. Check if the Code is Running on the Client Side

You can use the typeof window !== 'undefined' check to ensure the code runs only in the browser.

import { useEffect, useState } from 'react';

export default function ClientComponent() {
  const [windowWidth, setWindowWidth] = useState(0);

  useEffect(() => {
    // Ensure this runs only on the client side
    if (typeof window !== 'undefined') {
      setWindowWidth(window.innerWidth);

      const handleResize = () => {
        setWindowWidth(window.innerWidth);
      };

      window.addEventListener('resize', handleResize);

      // Cleanup the event listener
      return () => {
        window.removeEventListener('resize', handleResize);
      };
    }
  }, []);

  return <div>Window Width: {windowWidth}px</div>;
}

2. Use Dynamic Imports for Client-Side Only Code

If you need to import a library or component that relies on browser APIs, you can use Next.js's dynamic import with the ssr: false option to ensure it only loads on the client side.

import dynamic from 'next/dynamic';

// Load this component only on the client side
const ClientOnlyComponent = dynamic(() => import('../components/ClientOnlyComponent'), {
  ssr: false,
});

export default function Home() {
  return (
    <div>
      <h1>Home Page</h1>
      <ClientOnlyComponent />
    </div>
  );
}

3. Access Browser APIs in useEffect

Since useEffect runs only on the client side after the component mounts, it's a safe place to use browser APIs.

import { useEffect, useState } from 'react';

export default function LocalStorageExample() {
  const [value, setValue] = useState('');

  useEffect(() => {
    // Access localStorage only on the client side
    if (typeof window !== 'undefined') {
      const storedValue = localStorage.getItem('myKey');
      if (storedValue) {
        setValue(storedValue);
      }
    }
  }, []);

  const saveToLocalStorage = () => {
    if (typeof window !== 'undefined') {
      localStorage.setItem('myKey', 'Hello, LocalStorage!');
      setValue('Hello, LocalStorage!');
    }
  };

  return (
    <div>
      <p>Stored Value: {value}</p>
      <button onClick={saveToLocalStorage}>Save to LocalStorage</button>
    </div>
  );
}

4. Use the useClient Hook (Optional)

If you're using React Server Components (RSC) in Next.js 13+, you can mark a component as client-side only by adding the 'use client' directive at the top of the file.

'use client'; // Mark this component as client-side only

import { useEffect, useState } from 'react';

export default function ClientComponent() {
  const [mounted, setMounted] = useState(false);

  useEffect(() => {
    setMounted(true);
  }, []);

  if (!mounted) {
    return <div>Loading...</div>;
  }

  return <div>Browser API is available!</div>;
}

5. Avoid Direct Usage in Render

Never directly use browser APIs in the render phase of a component, as this will cause errors during SSR.

// โŒ Avoid this
export default function BadExample() {
  const width = window.innerWidth; // This will break during SSR

  return <div>Window Width: {width}px</div>;
}

  1. Don't create Next.js client components to high in your component tree