skip to Main Content

Building an infinite scroll in next.js, I am trying to call my serverAction to loadMoreData and using async/await with it to wait for the API call and get result.

Getting an error:

"async/await is not yet supported in Client Components, only Server Components."

page.tsx is a server component and calls the same server action one time for initial images.

// page.tsx

const Home = async ({ searchParams }) => {

  const searchKeyword =
    typeof searchParams.keyword === "string" ? searchParams.keyword : "";
  
  let apiResponse = await getPhotos({ query: searchKeyword });

  return (
    <main className='p-6 flex justify-center w-full min-h-screen bg-black'>
      <InfiniteScrollData
        search={searchKeyword}
        initialData={apiResponse?.results || []}
      />
    </main>
  );
};

export default Home;

Here is the server action:

// actions.ts

"use server";


export const getData = async ({
  query,
}) => {
  
  const { response } = await fetchData({
    query,
  });
  apiResponse = response;
  
  return response;
};

And following is the client component

// InfiniteScrollData.tsx

"use client";

// imports


const InfiniteScrollImages: = ({
  search,
  initialData,
}) => {
  const [data, setData] = useState(initialData);
  const [page, setPage] = useState(1);
  const [loaderRef, inView] = useInView();

  const loadMoreData = useCallback(async () => {
    const next = page + 1;
    const response = await getData({ query: search, page: next });
    if (response?.results?.length) {
      setPage(next);
      setData((prev) => [...prev, ...(response?.results || [])]);
    }
  }, [page, search]);

  useEffect(() => {
    if (inView) {
      loadMoreData();
    }
  }, [inView, loadMoreData]);

  return (
    <>
      <div>
        {photos?.map((item) => (
          <Card key={item.id} data={item} />
        ))}
      </div>
      <div ref={loaderRef}>
        <Loader />
      </div>
    </>
  );
};

export default InfiniteScrollImages;


Using [email protected]

Maybe there is another way of calling server actions from client components?

2

Answers


  1. Your error directly says that you cannot do await functions in client components, so you should find away to get rid of that in your code:

    const Home = ({ searchParams }) => { // no async 
    
    Login or Signup to reply.
  2. As the error suggested async await isn’t supported in client components.
    Your alternative would be to handle promises. Your getData async function returns a promise which you can handle in your useCallback or just return the promise there as well and handle the promise in the useEffect

    Without a demo I am kind of guessing so here is a rough solution:

    const loadMoreData = useCallback(() => {
        const next = page + 1;
        getData({ query: search, page: next }).then(response => {
          if (response?.results?.length) {
            setPage(next);
            setData((prev) => [...prev, ...(response?.results || [])]);
          }
        }).error(() => {
    
        });
      }, [page, search]);
    

    On Nextjs documentation for client data fetching this is the example they give:

    import { useState, useEffect } from 'react'
    
      function Profile() {
        const [data, setData] = useState(null)
        const [isLoading, setLoading] = useState(true)
    
        useEffect(() => {
          fetch('/api/profile-data')
            .then((res) => res.json())
            .then((data) => {
              setData(data)
              setLoading(false)
            })
        }, [])
    
        if (isLoading) return <p>Loading...</p>
        if (!data) return <p>No profile data</p>
    
        return (
          <div>
            <h1>{data.name}</h1>
            <p>{data.bio}</p>
          </div>
        )
      }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search