Understanding ‘useClient’ and ‘useServer’ in Next.js

useClient and useServer are React hooks introduced in Next.js to optimize and clarify the execution context of components or logic within an application. These hooks are part of Next.js’s ongoing enhancements to support React Server Components, enabling developers to specify more clearly whether a component should run on the client-side or server-side.

useServer

The useServer hook is a clear indication that the enclosed code or component is intended to run only on the server. This is particularly useful for operations that are sensitive or need direct access to server-side resources such as databases or environment variables that should not be exposed to the client. Here’s a quick example:

'use server'

function ServerComponent() {
  const data = useServer(() => {
    // Fetch data or perform operations that are server-only
    return fetchSecretData();
  });

  return <div>Secret Data: {data}</div>;
}
import { useServer } from 'next/server';

function ServerComponent() {
  const serverData = useServer(() => {
    // Simulate fetching server-only data
    const data = fetchServerData();
    return data;
  });

  return <div>Loaded server-only data: {serverData}</div>;
}

function fetchServerData() {
  // Pretend to fetch data that should not be exposed to the client
  return "Secret server info";
}

In this example, fetchSecretData is a function that you wouldn’t want to expose to the client-side due to security concerns or computational reasons. By using useServer, you ensure that this function only runs on the server.

useClient

Conversely, useClient is used to denote that the enclosed code or component should run only on the client-side. This is suitable for interactions that depend solely on the browser’s capabilities, such as DOM manipulations or client-side state handling that doesn’t need to pre-render on the server. Here’s how you might use it:

'use client'

function ClientComponent() {
  const [count, setCount] = useClient(() => {
    // Only run this hook in the client-side environment
    const [localCount, setLocalCount] = useState(0);
    return [localCount, setLocalCount];
  });

  return (
    <div>
      <button onClick={() => setCount(count + 1)}>Increment</button>
      Count: {count}
    </div>
  );
}
import { useClient } from 'next/client';
import { useState } from 'react';

function ClientComponent() {
  const [count, setCount] = useClient(() => {
    // Initialize state only on the client
    const [localCount, setLocalCount] = useState(0);
    return [localCount, setLocalCount];
  });

  // Button click handler for incrementing the count
  function handleClick() {
    setCount(count + 1);
  }

  return (
    <div>
      <button onClick={handleClick}>Increment</button>
      Count: {count}
    </div>
  );
}

In this example, the state management for count is purely client-side, which makes useClient ideal for encapsulating client-specific logic.

When to Use useServer vs. useClient

Deciding whether to use useServer or useClient boils down to understanding where your code needs to execute for optimal performance and security. Here are some guidelines:

  • Use useServer if:
    • You need to access server-side resources or perform actions securely, away from the client’s reach.
    • You want to pre-render data or perform computations during server-side rendering (SSR) for SEO benefits or faster page loads.
  • Use useClient if:
    • Your component or logic must interact with browser-specific APIs or client-side resources like the local storage.
    • You are handling state or effects that should only occur in the client’s environment, such as animations or user input events.