Skip to content

Next.js error

You're Importing a Component That Needs useState

The error

You're importing a component that needs `useState`. This React hook only works in a client component. To fix, mark the file (or its parent) with the `"use client"` directive.

The error suggests a fix and most people apply it to the wrong file. Which file gets the directive decides how much JavaScript your users download.

Every component in the App Router is a Server Component by default. Server Components render once, on the server, and never re-render - so they have no state, no effects, no event handlers and no hooks.

The error is correct and its suggested fix is correct. What it cannot tell you is which file to put the directive in, and that decision is the whole cost.

The directive marks a boundary, not a file

'use client' does not apply to one component. Everything that file imports, and everything those files import, joins the client bundle with it.

So the two obvious placements have very different prices:

app/page.tsx                    'use client'  ← everything below ships
  ├─ <Hero />                   ships
  ├─ <FeatureGrid />            ships
  ├─ <Testimonials />           ships
  └─ <NewsletterForm />         ships (this is the one that needed useState)
app/page.tsx                    Server Component
  ├─ <Hero />                   HTML only
  ├─ <FeatureGrid />            HTML only
  ├─ <Testimonials />           HTML only
  └─ <NewsletterForm />         'use client'  ← only this ships

Same page, same behaviour, materially different First Load JS. The first version is what you get by putting the directive where the error pointed.

The fix

Extract the interactive part into its own file, mark that file, and leave the page a Server Component:

// app/newsletter-form.tsx
'use client';
import { useState } from 'react';
 
export function NewsletterForm() {
  const [email, setEmail] = useState('');
  // ...
}

Then import it from the page as usual. A Server Component can render a Client Component; the reverse is what needs care.

Passing server data down

A Client Component can receive props from a Server Component, as long as they serialise. Data crosses; behaviour does not. If you need to pass something that is not plain data, that is a different error with a different fix.

You can also pass server-rendered markup through, which is the pattern people miss:

// Server Component
<Accordion>            {/* 'use client' */}
  <ExpensiveServerRenderedContent />   {/* stays on the server */}
</Accordion>

Children are rendered before they reach the client component, so the wrapper can be interactive without dragging its contents into the bundle.

Measuring whether it mattered

next build prints First Load JS per route. Move a directive down a level, build again, and compare - the number is the argument. In most codebases we read, the boundary has drifted upward one accident at a time, and what that costs is the same measurement across every route.

Related questions

Does 'use client' mean the component is not server-rendered?
No, and this is the most common misreading. Client Components are still rendered to HTML on the server. The directive marks where hydration begins - the component also ships as JavaScript, which is the cost.
Do I need it in every file that uses hooks?
Only at the boundary. Files imported by a Client Component are client-side already; the directive at the top of the tree covers them. Repeating it lower down is harmless but says nothing new.