Next.js Discord

Discord Forum

Fetch inside a client component?

Answered
Swedish Lapphund posted this in #help-forum
Open in Discord
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:

'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} ... />
}
View full answer

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 useEffect and calling fetch direct in the event handler function
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 handler
Swedish 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