reactjs 如何在next.js中将异步页面组件呈现为子组件?

5kgi1eie  于 2023-04-05  发布在  React
关注(0)|答案(2)|浏览(123)

我正在使用next.js的新功能来渲染使用SSR的内容,我正在制作async组件,正如docs所说。
这就是我的简单页面组件

export default async function Home() {

    const res = await fetch("http://localhost:3000/api/get-quotes");
    const quotes = await res.json();

    return (
        <main className={styles.main}>
            <h1>Hello Visrut</h1>
            <div>
                <span>Total quotes: {quotes.length}</span>
            </div>
        </main>
    )
}

我的应用程序中有authenticatednon-authenticated路由,我正在执行的操作是在_app.tsx中分离它们

// _app.tsx
interface AppProps {
  Component: React.ElementType;
  pageProps: Record<string, unknown>;
}

const App: React.FC<AppProps> = ({ Component, pageProps }) => {
  const router = useRouter();

  if (router.pathname.includes("home")) {
    return <Home />;   // Error: 'Home' can't be used as a JSX component, Its return type Promise<Home> is not a valid JSX component.
  }

  return (
    <AuthContextProvider>
      <Navbar />
      <Head />
      <Component {...pageProps} />
      <Footer />
    </AuthContextProvider>
  )
};

export default App;

我想呈现不需要身份验证的Home组件,因为async关键字,我似乎不能直接将其作为子组件。
我也得到这个错误的浏览器,而直接渲染async组件到其他正常组件在next.js

Error: Objects are not valid as a React child (found: [object Promise]). If you meant to render a collection of children, use an array instead.
mdfafbf1

mdfafbf11#

将异步代码移动到getServerSideProps函数中,并将响应作为Props传递到Home组件中

下一页12

参考:https://nextjs.org/docs/basic-features/data-fetching/get-server-side-props

export async function getServerSideProps() {
  const res = await fetch("http://localhost:3000/api/get-quotes");
  const quotes = await res.json();

  return {
    props: {
      quotes: quotes,
    }, // will be passed to the page component as props
  };
}
export default function Home({quotes}) {
    return (
        <main className={styles.main}>
            <h1>Hello Visrut</h1>
            <div>
                <span>Total quotes: {quotes.length}</span>
            </div>
        </main>
    )
}

下一页13

import { use } from "react";

async function getQuotes() {
  return await fetch("http://localhost:3000/api/get-quotes", {
    cache: "no-store",
  }).json();
}

export default function Home() {
  const quotes = use(getQuotes());
  return (
    <main className={styles.main}>
      <h1>Hello Visrut</h1>
      <div>
        <span>Total quotes: {quotes.length}</span>
      </div>
    </main>
  );
}
np8igboo

np8igboo2#

您的代码中存在一些概念问题
你不能有像那样的异步组件,组件必须是同步函数,要解决这个问题你有一些方法

**使用useEffect:**你可以在一个处理这些异步问题的效果中调用fetch,就像这样:

import { useState, useEffect } from 'react';

export default function Home() {
    const [quotes, setQuotes] = useState([])
    const [loading, setLoading] = useState(true)

    useEffect(() => {
      const getData = async () => {
        const res = await fetch("http://localhost:3000/api/get-quotes");
        const data = await res.json();
        setQuotes(data)
        setLoading(false)
      }
      getData();
      return () => {
        // here you can clean the effect in case the component gets unmonth before the async function ends
      }
    },[])

    if (loading) {
      return <>loading...</>
    }

    return (
        <main className={styles.main}>
            <h1>Hello Visrut</h1>
            <div>
                <span>Total quotes: {quotes.length}</span>
            </div>
        </main>
    )
}

使用Next中的SSR看看https://nextjs.org/docs/basic-features/data-fetching/overview,你可以在这里看到一些在渲染页面之前获取数据的选项,这很棒,这里有一个例子:

import { useRouter } from 'next/router'

export default function Home({data}) {
    const router = useRouter();

    if (!router.isReady) {
      return <>loading...</>
    }

    return (
        <main className={styles.main}>
            <h1>Hello Visrut</h1>
            <div>
                <span>Total quotes: {data.length}</span>
            </div>
        </main>
    )
}

export const getServerSideProps = async () => {
  const res = await fetch("http://localhost:3000/api/get-quotes");
  const data = await res.json();

  return {
    props: {
      data,
    },
  }
}

这将解决你提到的问题,但你也有一个关于_app文件的概念问题,你想限制导航的方式,看起来你想让布局(导航栏,页脚等)只在它不在家的时候呈现,所以这将是这样的:

const App: React.FC<AppProps> = ({ Component, pageProps }) => {
  const router = useRouter();

  if (router.pathname.includes("home")) {
    return <Component {...pageProps} />
  }

  return (
    <AuthContextProvider>
      <Navbar />
      <Head />
      <Component {...pageProps} />
      <Footer />
    </AuthContextProvider>
  )
};

然而,这只限制了它根据每条路线显示的视觉效果,在这里你并没有真正验证你是否有一个活动的会话,但是嘿,我希望它能帮助你!

相关问题