Fetch inside a client component?
Answered
Swedish Lapphund posted this in #help-forum
Swedish LapphundOP
I'm a little confused when it comes to client components that need to make server calls. For example, I have made the following button for testing client components inside server components:
It simply changes the text of the button when clicked. Works.
As you can see it gets the new text from function
To do this, I need to use
I tried making the Ping function asynchronous, but that throws the following error:
'use client'
import { Button } from "@/components/ui/button"
import { useState } from "react"
function Ping() {
return "Pong"
}
export function ClientButton() {
const [isClicked, setIsClicked] = useState(false)
const [buttonText, setButtonText] = useState("Ping")
function handleButtonClick() {
setIsClicked(true)
setButtonText(Ping)
}
if(isClicked) {
return (
<Button disabled variant="secondary">{buttonText}</Button>
)
} else {
return (
<Button onClick={handleButtonClick} variant="default">{buttonText}</Button>
)
}
}It simply changes the text of the button when clicked. Works.
As you can see it gets the new text from function
Ping(). In the new scenario, I want to make a call to my server using fetch. The call will also return "Pong". Very simple.To do this, I need to use
await fetch which needs to be in a async function. But async functions are not allowed in client components as I understand it. How do I handle this?I tried making the Ping function asynchronous, but that throws the following 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.Answered by Rafael Almeida
const Button = () => {
const handleClick = async () => {
const res = await fetch(...).json()
console.log(res)
}
return <button onClick={handleClick} ... />
}9 Replies
@Swedish Lapphund I'm a little confused when it comes to client components that need to make server calls. For example, I have made the following button for testing client components inside server components:
js
'use client'
import { Button } from "@/components/ui/button"
import { useState } from "react"
function Ping() {
return "Pong"
}
export function ClientButton() {
const [isClicked, setIsClicked] = useState(false)
const [buttonText, setButtonText] = useState("Ping")
function handleButtonClick() {
setIsClicked(true)
setButtonText(Ping)
}
if(isClicked) {
return (
<Button disabled variant="secondary">{buttonText}</Button>
)
} else {
return (
<Button onClick={handleButtonClick} variant="default">{buttonText}</Button>
)
}
}
It simply changes the text of the button when clicked. Works.
As you can see it gets the new text from function `Ping()`. In the new scenario, I want to make a call to my server using `fetch`. The call will also return "Pong". Very simple.
To do this, I need to use `await fetch` which needs to be in a async function. But async functions are not allowed in client components as I understand it. How do I handle this?
I tried making the Ping function asynchronous, but that throws the following 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.
it is the same thing as you would do before RSC: https://react.dev/reference/react/useEffect#fetching-data-with-effects
in your case since you are firing a request from an user interaction, you can avoid using an
in your case since you are firing a request from an user interaction, you can avoid using an
useEffect and calling fetch direct in the event handler function@Rafael Almeida it is the same thing as you would do before RSC: <https://react.dev/reference/react/useEffect#fetching-data-with-effects>
in your case since you are firing a request from an user interaction, you can avoid using an `useEffect` and calling `fetch` direct in the event handler function
Swedish LapphundOP
But the event handler function must be
async in order to work with await fetch must it not?yeah, that works. or if you want you could also use the old then/catch method
Swedish LapphundOP
But next doesnt allow me to execute async functions in a client component, thats the issue.
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.you dont add
async in the component, you only add it in the button handlerSwedish LapphundOP
Being pretty new to next I dont fully understand what you mean by that. Do you mean making the function like "handleButtonClick" async would work?
yeah
const Button = () => {
const handleClick = async () => {
const res = await fetch(...).json()
console.log(res)
}
return <button onClick={handleClick} ... />
}Answer
to be clear, this is not specific to next, that's how you do in any react app. but for production apps you will want to handle loading and error states which make this more complex, at this point you would use something like
swr or react-query instead to handle all the complexity for you