skip to Main Content

I am new to NextJS so the question might sound a trivial so please bear with me. So, basically I want to fetch data from a database and display it in the page at the first render and for that I am trying to use useEffect and useState hooks as follows.

"use client"
import axios from "axios"
import Link from "next/link"
import { useEffect } from "react"
async function ProductsComponent( ) {
    const [products,setProducts] = useState<any[]>([])
    useEffect(()=>{
        async function fetchProducts() {
             "use server"
            try {
                const productsresponse = await axios.get(`${process.env.BASE_URL}/api/productControllers`)
                if(productsresponse.status === 200){
                    setProducts(productsresponse.data.message)
                }else{
                    console.log("Failed to fetch Products")
                }
            } catch (error) {
                
            }
        }
        fetchProducts()
    },[])
    return (
      <div className=" flex flex-col">
        <h3>Product Name</h3>
        {
            products?.map(product=>(
                <div>
                    <h4>{product?.productName}</h4>
                 </div>
                </div>
            ))
        }
      </div>
    )
  }
  
  export default ProductsComponent

but I get an error of:

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

and if i remove the "use client", I get an error of:

You’re importing a component that needs useState. It only works in a Client Component but none of its parents are marked with "use client", so they’re Server Components by default.

So how can I ever fetch data from database and render it in NextJS >=13 ?

I tried defining a separate server side function component that fetches data from database using useEffect and the compoentnt takes the product and setproduct as props and I passed the component in anohter client component where we define states like product ,setProduct but I am still getting an error.

2

Answers


  1. Try removing the 'use server' from the async function because "use server" functions are not allowed in client components. You can create a ‘use server’ file and You can import them from a "use server" file instead.

    Updated Code:

    useEffect(()=>{
        async function fetchProducts() {
            try {
                const productsresponse = await axios.get(`${process.env.BASE_URL}/api/productControllers`)
                if(productsresponse.status === 200){
                    setProducts(productsresponse.data.message)
                }else{
                    console.log("Failed to fetch Products")
                }
            } catch (error) {
                
            }
        }
        fetchProducts()
    },[])
    

    Simply removing ‘use server’ worked for me, hoping it will also works for you.

    Login or Signup to reply.
  2. There are two ways to render a page:

    • Client Side – client gets page & it makes api call & then sets data
      in page.

    • Server side – server gets data & generates page & then sends it to
      the client.

      Two solutions :

    • Client side rendering, make a component with 'use client' at top of
      it & import it in your page.

    • Server side rendering (make page on server & then send to client)

    By default Next.js considers a component as Server Component.
    Hence it throws a error when u remove 'use client' from a component which uses (useEffect,useState etc. as this are hydrated/calculated on client side)

    You're importing a component that needs useState. It only works in a Client Component but none of its parents are marked with "use client", so they're Server Components by default.
    

    https://nextjs.org/docs/app/building-your-application/rendering/server-components#using-server-components-in-nextjs

    When you use use client you make it as client component.
    https://nextjs.org/docs/app/building-your-application/rendering/client-components#using-client-components-in-nextjs

    Read more about Rendering : https://nextjs.org/docs/app/building-your-application/rendering

    Here is code with both implementations.

    Folder Structure :

    projectName
    ├── .gitignore
    ├── jsconfig.json
    ├── next.config.js
    ├── package-lock.json
    ├── package.json
    ├── postcss.config.js
    ├── public
    │   ├── images
    │   ├── next.svg
    │   └── vercel.svg
    ├── README.md
    ├── src
    │   └── app
    │       ├── api
    │       ├── comp
    │       │   └── ProductsList.js
    │       ├── favicon.ico
    │       ├── globals.css
    │       ├── layout.js
    │       ├── page.js
    │       ├── products
    │       │   └── page.js
    │       └── products_clientside
    │           └── page.js
    └── tailwind.config.js
    
    • Server side rendering

    locsrcappproductspage.js

    import axios from "axios";
    
    async function GetProducts() {
        let { data } = await axios.get('https://dummyjson.com/products')
        return data
    }
    
    export default async function ProductsPage() {
    
    
        let Products = await GetProducts();
        console.log("Data from API on Serverside :", Object.keys(Products));
        // console.log("Products on Serverside :", Products.products);
    
        return (
            <div>
                <h1>Products Page (Serverside Fetching)</h1>
                {
                    Products
    
                        ?
                        Products.products.map((p, i) => {
                            return (
                                <p key={i}>{p.title}</p>
                            )
                        })
                        :
    
                        "Getting Products ...."
    
    
                    // THIS LOADING STATE WILL NOT BE VISIBLE BECAUSE SERVER LOADS THIS WHOLE PAGE
                }
            </div>
        )
    }
    

    Output :

    • Go on route http://localhost:3000/products
    • you will see data console.log() in terminal (there 2 console logs 1 is to show keys present in data, other is commented out )

    —————————————————————————–

    Client side rendering:

    • Make a component in comp folder.

    ProductsList Component locsrcappcompProductsList.js

    'use client'
    import axios from 'axios'
    import React, { useEffect, useState } from 'react'
    
    const ProductsList = () => {
    
        async function GetProducts() {
            let { data } = await axios.get('https://dummyjson.com/products')
            console.log(data);
            SetProducts(data)
        }
    
        const [Products, SetProducts] = useState(null)
    
        useEffect(() => {
            GetProducts()
        }, [])
    
        return (
            <div>
                <h1>Products Page</h1>
                {
                    Products
    
                        ?
                        Products.products.map((p, i) => {
                            return (
                                <p key={i}>{p.title}</p>
                            )
                        })
                        :
    
                        "Getting Products ...."
    
                    // THIS LOADING STATE WILL  BE VISIBLE BECAUSE CLIENT LOADS A SECTION OF PAGE 
    
                }
            </div>
        )
    }
    
    export default ProductsList
    

    Now make a page locsrcappproducts_clientsidepage.js & import ProductsList

    import ProductsList from "../comp/ProductsList"
    const page = () => {
        return (
            <div>
                <h1> Product Page Other Way (Client Side Fetching)</h1>
                <ProductsList />
            </div>
        )
    }
    export default page
    

    Output :

    • Go to url http://localhost:3000/products_clientside
    • You will see "Getting Products ...." & also in console the data recieved from api
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search