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/awaitdirectly in your component. - Remove the
asynckeyword: If you need to keep it as a Client Component, remove theasynckeyword and handle data fetching differently. - Use React Hooks for data fetching: Utilize hooks like
useEffectfor client-side data fetching, or use third-party libraries. - Leverage the
usehook with a Context Provider: Pass promises to child components using context, then resolve them with theusehook.
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?