javascriptreactjsnext.jswebpackstatic-site-generation

How to use useState without "use client" in Next.js when I use generateStaticParams


I need this in an SSG to send to photo galleries the image files' dimensions. I expected no error.

Error of "npm run dev":

21:23:44 ~/Desktop/Pro/home-gh-pages main $ npm run dev

> home-gh-pages@0.1.0 dev
> next dev

   ▲ Next.js 15.2.5
   - Local:        http://localhost:3000
   - Network:      http://192.168.1.100:3000

 ✓ Starting...
 ✓ Ready in 1593ms
 ○ Compiling / ...
 ⨯ ./src/app/page.tsx
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.
  │ 
  │  Learn more: https://nextjs.org/docs/app/api-reference/directives/use-client
  │ 
  │ 
    ╭─[/home/silviub/Desktop/Pro/home-gh-pages/src/app/page.tsx:14:1]
 11 │ import Thumbnails from "yet-another-react-lightbox/plugins/thumbnails";
 12 │ import Zoom from "yet-another-react-lightbox/plugins/zoom";
 13 │ import "yet-another-react-lightbox/plugins/thumbnails.css";
 14 │ import { useState } from "react";
    ·          ────────
 15 │ 
 16 │ import LiteYouTubeEmbed from 'react-lite-youtube-embed';
 17 │ import 'react-lite-youtube-embed/dist/LiteYouTubeEmbed.css';
    ╰────

Import trace for requested module:
./src/app/page.tsx
 ⨯ ./src/app/page.tsx
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.
  │ 
  │  Learn more: https://nextjs.org/docs/app/api-reference/directives/use-client
  │ 
  │ 
    ╭─[/home/silviub/Desktop/Pro/home-gh-pages/src/app/page.tsx:14:1]
 11 │ import Thumbnails from "yet-another-react-lightbox/plugins/thumbnails";
 12 │ import Zoom from "yet-another-react-lightbox/plugins/zoom";
 13 │ import "yet-another-react-lightbox/plugins/thumbnails.css";
 14 │ import { useState } from "react";
    ·          ────────
 15 │ 
 16 │ import LiteYouTubeEmbed from 'react-lite-youtube-embed';
 17 │ import 'react-lite-youtube-embed/dist/LiteYouTubeEmbed.css';
    ╰────

Import trace for requested module:
./src/app/page.tsx
 ⨯ ./src/app/page.tsx
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.
  │ 
  │  Learn more: https://nextjs.org/docs/app/api-reference/directives/use-client
  │ 
  │ 
    ╭─[/home/silviub/Desktop/Pro/home-gh-pages/src/app/page.tsx:14:1]
 11 │ import Thumbnails from "yet-another-react-lightbox/plugins/thumbnails";
 12 │ import Zoom from "yet-another-react-lightbox/plugins/zoom";
 13 │ import "yet-another-react-lightbox/plugins/thumbnails.css";
 14 │ import { useState } from "react";
    ·          ────────
 15 │ 
 16 │ import LiteYouTubeEmbed from 'react-lite-youtube-embed';
 17 │ import 'react-lite-youtube-embed/dist/LiteYouTubeEmbed.css';
    ╰────

Import trace for requested module:
./src/app/page.tsx
 ⨯ ./src/app/page.tsx
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.
  │ 
  │  Learn more: https://nextjs.org/docs/app/api-reference/directives/use-client
  │ 
  │ 
    ╭─[/home/silviub/Desktop/Pro/home-gh-pages/src/app/page.tsx:14:1]
 11 │ import Thumbnails from "yet-another-react-lightbox/plugins/thumbnails";
 12 │ import Zoom from "yet-another-react-lightbox/plugins/zoom";
 13 │ import "yet-another-react-lightbox/plugins/thumbnails.css";
 14 │ import { useState } from "react";
    ·          ────────
 15 │ 
 16 │ import LiteYouTubeEmbed from 'react-lite-youtube-embed';
 17 │ import 'react-lite-youtube-embed/dist/LiteYouTubeEmbed.css';
    ╰────

Import trace for requested module:
./src/app/page.tsx
 GET / 500 in 326ms

If I use "use client" page.tsx (tested from new index.tsx too) I get error:

21:33:49 ~/Desktop/Pro/home-gh-pages main $ npm run dev

> home-gh-pages@0.1.0 dev
> next dev

   ▲ Next.js 15.2.5
   - Local:        http://localhost:3000
   - Network:      http://192.168.1.100:3000

 ✓ Starting...
 ✓ Ready in 1627ms
 ○ Compiling /_not-found ...
 ✓ Compiled /_not-found in 1323ms (660 modules)
 ⚠ Fast Refresh had to perform a full reload due to a runtime error.
 GET /_next/static/webpack/93bd01d6b78ae12e.webpack.hot-update.json 404 in 1595ms
 ⨯ [Error: Page "/page" cannot use both "use client" and export function "generateStaticParams()".]
 ○ Compiling /_error ...
 ✓ Compiled /_error in 788ms (989 modules)
 GET / 500 in 1194ms

Minimum, reproducible example: page.tsx:

"use client";

import { useState } from "react";

export default function Home() {
  const [x, setX] = useState(-1);
  return <p onClick={() => {
    setX(x + 1);
  }}>{x}</p>;
}

export const revalidate = 60;
export const dynamicParams = true;

export const generateStaticParams = async () => {
  return { data: 100 };
};

Throws Error: Page "/page" cannot use both "use client" and export function "generateStaticParams()".


Solution

  • // StatefulHome.tsx
    "use client";
    
    import { useState } from "react";
    
    export function StatefulHome() {
      const [x, setX] = useState(-1);
      return <p onClick={() => {
        setX(x + 1);
      }}>{x}</p>;
    }
    
    // Home.tsx
    export default function Home() {
      return <><h1>Home</h1><StatefulHome /></>;
    }
    
    export const generateStaticParams = async () => {
      return { data: 100 };
    };
    

    In the question I meant using getStaticProps (actually the equivalent to it for app router) instead of generateStaticParams, which is useless in the above example.