如何获取数据并在NextJs 13或更高版本中显示?

tct7dpnv  于 2023-11-18  发布在  其他
关注(0)|答案(2)|浏览(154)

我是NextJS的新手,所以这个问题听起来可能很琐碎,所以请原谅我。所以,基本上我想从数据库中获取数据,并在第一次渲染时将其显示在页面中,为此,我尝试使用useEffect和useState钩子,如下所示。

"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

字符串
但我得到一个错误:

客户端组件暂不支持aprc/await,仅支持服务器组件。

如果我删除"use client",我会得到一个错误:

您正在导入一个需要useState的组件,它只在客户端组件中工作,但它的父组件都没有使用“use client”标记,因此默认为服务器组件。

那么我如何从数据库中获取数据并在NextJS >=13中呈现它呢?
我试着定义一个单独的服务器端函数组件,它使用useEffect从数据库中获取数据,该组件将product和setproduct作为props,我将该组件传递到另一个客户端组件中,在那里我们定义了像product,setProduct这样的状态,但我仍然得到一个错误。

dfty9e19

dfty9e191#

页面呈现方式有两种:

在第一次呈现时将其显示在页面中

**所以SSR将是要走的路,因为它将生成页面并将其发送到客户端。**没有加载状态,将被视为。

我使用的是NextJS版本:13.5.4
默认情况下,Next.js将组件视为服务器组件。但是当您在组件中使用use client时,您将其视为客户端组件。
https://nextjs.org/docs/app/building-your-application/rendering/server-components#using-server-components-in-nextjs
因此,当你从使用(useEffect,useState等)的组件中删除'use client'时,它会抛出一个错误,因为这是在客户端进行水合/计算的。
您正在导入一个需要useState的组件。它只在客户端组件中工作,但它的父组件都没有标记为“use client”,因此它们默认为服务器组件。

这是两个实现的代码。
文件夹结构:

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

字符串

*服务端渲染

loc\src\app\products\page.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>
    )
}

说明:

  • 服务器端在渲染这个页面的时候,GetProducts()在服务器端被调用,服务器端等待,获取数据并生成整个页面,最后发送给客户端。
  • 客户端在此期间的渲染,只是看到一个空白的屏幕,加载指示器在浏览器中。
    输出:
  • 沿http://localhost:3000/products路线行驶
  • 你会在终端中看到data console.log()(有2个控制台日志1是显示数据中存在的键,其他的被注解掉)
    -----------------------------------------------------------------------------
    客户端渲染:
  • 在comp文件夹中创建一个组件。
    产品列表组件loc\src\app\comp\ProductsList.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


现在创建一个页面loc\src\app\products_clientside\page.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

说明:

  • 客户端获取页面,然后useEffect运行并调用API,显示Getting Products ....,当它获取数据集时显示。
    输出:
  • 转到URL http://localhost:3000/products_clientside
  • 您将看到"Getting Products ....",并且在控制台中还显示从API接收的数据
  • 进入控制台旁边的网络选项卡,打开此页面,您将在名称下看到products_clientside,单击它,然后在右侧单击Preview Tab,您将看到页面呈现,直到
  • 产品页面其他方式(客户端获取)产品页面获取产品....之后,产品状态由客户端设置和渲染(客户端渲染-浏览器执行)
  • 如果您有任何疑问,请留下评论(如有必要,我会更新 * 答案)*
pvabu6sv

pvabu6sv2#

请尝试将'use server''use server'函数中删除,因为客户端组件中不允许使用“use server”函数。您可以创建一个“use server”文件,然后从“use server”文件导入它们。

更新代码:

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()
},[])

字符串
简单地删除'使用服务器'为我工作,希望它也将为您工作。

相关问题