Skip to content

Client components in Next.js

Understanding Client Components ('use client')

Next.js App Router applications primarily render components on the server by default (these are Server Components). This is great for performance, SEO, and security. However, many parts of a web application need interactivity, browser APIs, or state management that can only happen on the client-side. This is where Client Components come in.

What is a Client Component?

A Client Component is a React component that is rendered on the client-side (in the user's browser). While they might initially be rendered on the server for the first page load (a process called hydration), their primary purpose is to enable interactivity, manage state, and access browser-specific APIs (like window or localStorage).

When and Why to Use 'use client'

You should mark a component as a Client Component using the 'use client' directive at the very top of the file when it needs:

  • Interactivity: Handling user interactions like clicks, input changes, hover effects.
  • State Management: Using React Hooks like useState or useReducer.
  • Lifecycle Effects: Using useEffect to perform side effects that run in the browser.
  • Browser-specific APIs: Accessing window, document, localStorage, etc.
  • Custom Hooks: If a custom hook uses useState or useEffect, any component using that hook must be a Client Component.

The 'use client' directive acts as a "boundary" between Server Components and Client Components. All modules imported into a Client Component are considered Client Components themselves, or can be Server Components that are then "passed" into the Client Component as props.

How to Mark a Component as a Client Component

To mark a component as a Client Component, simply add the string 'use client'; at the very top of the file, before any imports.

Let's demonstrate this by creating a simple interactive counter component.

  1. Create a new file for our counter component: components/Counter.tsx

    my-task-app/
    └── components/
        ├── Header.tsx
        ├── Footer.tsx
        ├── Counter.tsx       <-- NEW FILE
    

    components/Counter.tsx

    // components/Counter.tsx
    // This is a Client Component that demonstrates basic interactivity and state management.
    'use client'; // This directive marks the component as a Client Component.
    
    import { useState } from 'react'; // Import the useState hook
    
    export default function Counter() {
      // Use the useState hook to manage the 'count' state.
      // `count` holds the current value, `setCount` is a function to update it.
      const [count, setCount] = useState(0);
    
      // Event handler for incrementing the count
      const increment = () => {
        setCount(count + 1);
      };
    
      // Event handler for decrementing the count
      const decrement = () => {
        setCount(count - 1);
      };
    
      return (
        <div className="flex flex-col items-center p-6 bg-white rounded-lg shadow-md border border-gray-200">
          <h3 className="text-2xl font-bold text-gray-800 mb-4">Interactive Counter</h3>
          <p className="text-5xl font-extrabold text-blue-600 mb-6">{count}</p>
          <div className="flex space-x-4">
            <button
              onClick={decrement}
              className="px-6 py-3 bg-red-500 text-white rounded-lg shadow-md hover:bg-red-600 transition duration-300 transform hover:scale-105"
            >
              Decrement
            </button>
            <button
              onClick={increment}
              className="px-6 py-3 bg-green-500 text-white rounded-lg shadow-md hover:bg-green-600 transition duration-300 transform hover:scale-105"
            >
              Increment
            </button>
          </div>
        </div>
      );
    }
    
  2. Integrate Counter.tsx into app/page.tsx: Now, let's place our new Counter component on the homepage to see it in action.

    app/page.tsx (Update this file)

// app/page.tsx
// This file defines the content for the homepage ('/') of the application.
// Updated to include the Counter Client Component.

import Counter from '../components/Counter'; // Import the Counter component

export default function HomePage() {
    return (
    <div className="flex flex-col items-center justify-center min-h-[calc(100vh-250px)] text-center px-4 py-8 space-y-8">
        <h2 className="text-4xl md:text-5xl font-bold text-blue-700 mb-4 animate-fade-in">
        Welcome to My TaskFlow!
        </h2>
        <p className="text-xl text-gray-600 mb-8 max-w-2xl animate-slide-up">
        Your simple solution for organizing tasks and boosting productivity.
        </p>
        <p className="text-md text-gray-500">
        Get started by logging in or signing up to manage your daily tasks with ease.
        </p>

        {/* Add the Counter component here to demonstrate Client Components */}
        <Counter />
    </div>
    );
}

Summary

What we've done:

  • We've created a Counter.tsx component and explicitly marked it as a Client Component with 'use client'.
  • We've used the useState hook to manage its internal count state.
  • We've integrated this Client Component into our HomePage (which is a Server Component). This demonstrates that Server Components can import and use Client Components.

To see the Client Component in action:

  1. Ensure your development server is running (npm run dev).
  2. Open http://localhost:3000.
  3. Interact with the "Increment" and "Decrement" buttons on the counter. You'll see the count update dynamically on the page, demonstrating client-side interactivity.