No async client component
Client components cannot be async functions.
Why This Error Occurred
The error occurs when you try to define a client component as an async function. React client components do not support async functions. For example:
'use client'
// This will cause an error
async function ClientComponent() {
// ...
}
Possible Ways to Fix It
- Convert to a Server Component: If possible, convert your client component to a server component. This allows you to use
async
/await
directly in your component. - Remove the
async
keyword: If you need to keep it as a client component, remove theasync
keyword and handle data fetching differently. - Use React hooks for data fetching: Utilize hooks like
useEffect
for client-side data fetching, or use third-party libraries. - Leverage the
use
hook with a Context Provider: Pass promises to child components using context, then resolve them with theuse
hook.
Recommended: Server-side data fetching
We recommend fetching data on the server. For example:
export default async function Page() {
const data = await fetch('https://api.vercel.app/blog')
const posts = await data.json()
return (
<ul>
{posts.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
)
}
Using use
with Context Provider
Another pattern to explore is using the React use
hook with a Context Provider. This allows you to pass Promises to child components and resolve them using the use
hook . Here's an example:
First, let's create a separate file for the context provider:
'use client'
import { createContext, useContext } from 'react'
export const BlogContext = createContext<Promise<any> | null>(null)
export function BlogProvider({
children,
blogPromise,
}: {
children: React.ReactNode
blogPromise: Promise<any>
}) {
return (
<BlogContext.Provider value={blogPromise}>{children}</BlogContext.Provider>
)
}
export function useBlogContext() {
const context = useContext(BlogContext)
if (!context) {
throw new Error('useBlogContext must be used within a BlogProvider')
}
return context
}
Now, let's create the Promise in a Server Component and stream it to the client:
import { BlogProvider } from './context'
export default function Page() {
const blogPromise = fetch('https://api.vercel.app/blog').then((res) =>
res.json()
)
return (
<BlogProvider blogPromise={blogPromise}>
<BlogPosts />
</BlogProvider>
)
}
Here is the blog posts component:
'use client'
import { use } from 'react'
import { useBlogContext } from './context'
export function BlogPosts() {
const blogPromise = useBlogContext()
const posts = use(blogPromise)
return <div>{posts.length} blog posts</div>
}
This pattern allows you to start data fetching early and pass the Promise down to child components, which can then use the use
hook to access the data when it's ready.
Client-side data fetching
In scenarios where client fetching is needed, you can call fetch
in useEffect
(not recommended), or lean on popular React libraries in the community (such as SWR or React Query) for client fetching.
'use client'
import { useState, useEffect } from 'react'
export function Posts() {
const [posts, setPosts] = useState(null)
useEffect(() => {
async function fetchPosts() {
const res = await fetch('https://api.vercel.app/blog')
const data = await res.json()
setPosts(data)
}
fetchPosts()
}, [])
if (!posts) return <div>Loading...</div>
return (
<ul>
{posts.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
)
}
Was this helpful?