28

I am using next.js on "next": "13.4.19". the project structure is --app -- layout.tsx -- page.tsx -- [id] --page.tsx

in the [id] page.tsx,

"use client"

import { Editor } from '@/components/editor';
import { useState, useRef, useEffect, useMemo } from 'react'

export default async function PipelineDesignerEditorPage(
  { params }: { params: { pipelineId: string } }
) {
  console.log('params.pipelineId',params.pipelineId);

  const [loding, setLoding] = useState(false);
  const [pipelineData, setPipelineData] = useState({});

  useEffect(() => {
    setLoding(true);
    let data = getPipeline(params.pipelineId);
    setPipelineData(data);
    setLoding(false);
  }, []);

  return (
    <div style={{ width: '100%', height: `calc(100vh - 65px)` }}>
      <Editor pipeline={pipeline} />
    </div>
  )
}

an error 'Error: async/await is not yet supported in Client Components, only Server Components. This error is often caused by accidentally adding 'use client' to a module that was originally written for the server.' appears.

I found this page is being rendered in the server side, so I modified a bit

'user client'
import { Editor } from '@/components/editor';
import { getPipeline } from '@/lib/pipelines/storage';
import { useState, useRef, useEffect, useMemo } from 'react'

export default async function PipelineDesignerEditorPage(
  { params }: { params: { pipelineId: string } }
) {
  console.log('params.pipelineId',params.pipelineId);
  const pipeline = await getPipeline(params.pipelineId);
  
  const [loding, setLoding] = useState(false);
  useEffect(() => {
    console.log('useEffect');
    setLoding(true);
  }, []);

  return (
    <div style={{ width: '100%', height: `calc(100vh - 65px)` }}>
      <Editor pipeline={pipeline} />
    </div>
  )
}

it still doesn't work unless useEffect and useState is removed away.

Does it mean I can't use useState and useEffect in app->[id]->page.tsx, what about click, loading actions which needs to use useState and useEffect

1
  • 1
    Just remove the async keywords. Commented Dec 12, 2023 at 5:03

6 Answers 6

44

I used to get the same error when I tried applying 'use client' for the whole page.

My solution is removing the async keyword. In this case, use:

export default function PipelineDesignerEditorPage

instead of:

export default async function PipelineDesignerEditorPage
0
25

You are mixing client and server components. As the error says, async/await is only supported in server component (without "use client"). But, as you mentioned, useState and useEffect (or events like click) etc... are only supported in client components.

The solution is to split the 2 in 2 different components. Typically the page.tsx would be a server component where you fetch data and pass those to a child client component as parameter(s) where you can have state and events if needed.

On a specific note, you probably should have state and effect in the Editor or look at Suspense. See example under https://nextjs.org/docs/app/building-your-application/routing/loading-ui-and-streaming#example

4
  • 5
    But then how do you handle errors, loading states, etc? This is all coupled to the fetching logic... you need to set states while you are fetching/after you fetch. How are you supposed to do this without being able to use useState? You're supposed to change the whole way things are done and there is not even a simple example anywhere telling me how to do it? Ridiculous..
    – Bersan
    Commented Feb 12, 2024 at 3:20
  • Fetching is definitively NOT coupled to local state. You can fetch without setting state and can set state without fetching... If you need to put the fetched data in a local state, you fetch them in a server component and pass them in a client component where as props where it can be put in local state there. Then you can play with the state as you like there (without refetching when you update the state).
    – grekier
    Commented Feb 12, 2024 at 8:36
  • @grekier what if you just want to disable server side rendering all together? I know this is a huge benefit of Next.js, but we have a use case where we don't want it (i.e. static export only).
    – FooBar
    Commented Aug 13, 2024 at 10:59
  • Just to be clear: there is no server side rendering in the app router. Server Component is not the same as server side rendering. That being said, for full HTML file exported, use client components and fetch data in useEffect but set to the local state in .then() instead of await. You can also await inside useEffect by creating a new function inside the scope that you can async/await.
    – grekier
    Commented Aug 13, 2024 at 14:51
4

I got this error, when I accidentally define a function component as async function and call a valid async function inside of it.

async function MyComponent(){
   ...
   useEffect( () =>{
      asyncFunction().then(value => setInfo(value));
   },...)       
...
}

So just remove the async operator from the function component declaration and will work fine:

function MyComponent(){
   ...
   useEffect( () =>{
      asyncFunction().then(value => setInfo(value));
   },...)       
...
}
2

Fetching data in my page.tsx was quite frustrating as it would required me to do prop drilling. Fortunately, I discovered a more effective solution. By utilizing the dynamic function from the next/dynamic package, I was able to address the issue. Here's an example:

const ChatWelcomeContent = dynamic(() => import("./chat-welcome-content"), {
  ssr: true,
});

This resolves the error:

"Error: async/await is not yet supported in Client Components, only Server Components. This error is often caused by accidentally adding 'use client' to a module that was originally written for the server."

Hope it helps!

1
  • This works but the dynamically loaded component is still refreshing
    – Wilson
    Commented Jul 12, 2024 at 17:48
1

I used to get this error after changing the name of one prop and not updating the declaration in the parent component.

0

Dude, it might occur cuz your <Editor pipeline={pipeline} /> is a server component, in nextjs we can't import a server component in client component.

To fix this you just need go to the parent component of this PipelineDesignerEditorPage and pass <Editor /> component as a prop,

Or you can pass as a children also :

<PipelineDesignerEditorPage>
  <Editor />
</PipelineDesignerEditorPage>

and add children in this component :

'user client'
import { Editor } from '@/components/editor';
import { getPipeline } from '@/lib/pipelines/storage';
import { useState, useRef, useEffect, useMemo } from 'react'

export default async function PipelineDesignerEditorPage(
  { params, children }: { params: { pipelineId: string }; children : React.ReactNode}
) {
  console.log('params.pipelineId',params.pipelineId);
  const pipeline = await getPipeline(params.pipelineId);
  
  const [loding, setLoding] = useState(false);
  useEffect(() => {
    console.log('useEffect');
    setLoding(true);
  }, []);

  return (
    <div style={{ width: '100%', height: `calc(100vh - 65px)` }}>
      <Editor pipeline={pipeline} />
    </div>
  )
}

hope this helps..!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.