【问题标题】:How to do an async fetch before initial render如何在初始渲染之前进行异步获取
【发布时间】:2020-10-25 21:15:05
【问题描述】:

我目前正在前端使用 Next.js 使用 Wordpress API。我想获取我的导航/菜单数据并进行预渲染。我已经尝试过,但是当我检查源代码时,只呈现了一个空的 <nav> </nav> 元素。有没有简单的解决方案?

这是我的导航组件:

import { Config } from "../config";
import Link from "next/link";
import useFetch from "../hooks/useFetch";

    export default function MainNav() {
      const links = useFetch(`${Config.apiUrl}/wp-json/menus/v1/menus/main-nav`);
    
      return (
        <nav>
          {!!links &&
            links.map((link) => (
              <Link href="/">
                <a>{link.title}</a>
              </Link>
            ))}
        </nav>
      );
    }

还有我自定义的useFetch.js钩子:

import { useEffect, useState } from "react";

export default function useFetch(url) {
  const [links, setLinks] = useState();

  //   Must use useEffect in non-page component

  useEffect(async () => {
    let res = await fetch(url);
    res = await res.json();
    setLinks(res.items);
  }, []);

  return links;
}

【问题讨论】:

    标签: javascript reactjs async-await next.js headless-cms


    【解决方案1】:

    首先 useEffect 根本不是异步的,即使您在 useEffect 回调函数中定义 async ,正确的方法是为微调器设置单独的状态 - useState(false) 或包含它进入现有的一个,它将控制微调器,因为您正在通过 REST 获取数据,所以基本上完​​整的示例应该如下所示:

    useFetch.js钩子:

    import { useEffect, useState } from "react";
    
    export default function useFetch(url) {
      const [{ links, isLoading }, setLinks] = useState({ links: [], isLoading: true });
    
      //   Must use useEffect in non-page component
    
      useEffect(() => {
        (async funtion() {
          const res = await fetch(url);
          const { items } = await res.json();
          setLinks({ links: items, isLoading: false });
        })()
       
      }, []);
    
      return [isLoading, links];
    }
    
    

    Nav.js组件:

    import { Config } from "../config";
    import Link from "next/link";
    import useFetch from "../hooks/useFetch";
    
        export default function MainNav() {
          const [links, isLoading] = useFetch(`${Config.apiUrl}/wp-json/menus/v1/menus/main-nav`);
    
          if(isLoading) {
            return <Spinner/>
          }
        
          return (
            <nav>
              {!!links && !isLoading &&
                links.map((link) => (
                  <Link href="/">
                    <a>{link.title}</a>
                  </Link>
                ))}
            </nav>
          );
        }
    
    

    【讨论】:

    • 另外我将包含一篇文章,解释我们如何在 async 的帮助下获取数据 useEffect 钩子:robinwieruch.de/react-hooks-fetch-data
    • 嗨,感谢您的回答,因为我不知道 useEffect 使异步无效。但是,这对服务器端渲染没有帮助。
    • 好的,对于 SSR 解决方案,您需要在 Node.js 端发出请求,确切地说: 1. 在渲染所有内容之前,向 Headless CMS(Node.js 并附加东西到你的最终标记,只是一个 HTML 字符串)。 2. 收到响应后,创建静态 HTML,然后将其发送到 UI 3. 使 ReactDOM 水合预渲染的 makrup 4. 仅此而已,不幸的是,这对于 1 个静态菜单和老实说,我真的不知道你是否能够修补 Next.js SSR 渲染器并在那方面做自定义的东西
    • 我的解决方案要简单得多。我只是在页面上使用了getStaticProps(),然后通过组件组合将其传递给组件。缺点是组件需要对其子组件不可知。考虑到这不是一个庞大的项目,它似乎是最优雅的解决方案。
    【解决方案2】:

    所以我想通了,我在组件嵌套的页面上获取链接数据,然后使用组件组合将数据向下传递。问题是我必须直接将它们全部嵌套在页面上。如果有人有更优雅的解决方案,请告诉我:)

    页面index.js

    import PostIndex from "../components/PostIndex";
    import Layout from "../components/Layout";
    import Header from "../components/Header";
    import MainNav from "../components/MainNav";
    
    import { Config } from "../config";
    
    export default function Home(props) {
      return (
        <Layout>
          <Header>
            <MainNav links={props.links} />
          </Header>
          <h2>Home Page</h2>
          <PostIndex limit={3} />
        </Layout>
      );
    }
    
    export async function getServerSideProps() {
      const [data1, data2] = await Promise.all([
        fetch(`${Config.apiUrl}/wp-json/wp/v2/posts?per_page=3`),
        fetch(`${Config.apiUrl}/wp-json/menus/v1/menus/main-nav`),
      ]);
      const posts = await data1.json();
      const links = await data2.json();
      return {
        props: {
          posts,
          links,
        },
      };
    }
    

    Layout.js 组件:

    export default function Layout({ children }) {
      return <div>{children}</div>;
    }
    

    Header.js 组件:

    import Link from "next/link";
    
    export default function Header({ children }) {
      return (
        <div>
          <Link href="/">
            <a>
              <h1>Wordpress Blog</h1>
            </a>
          </Link>
          {children}
        </div>
      );
    }
    

    还有MainNev.js 组件:

    import { Config } from "../config";
    import Link from "next/link";
    
    export default function MainNav({ links }) {
      return (
        <nav>
          {!!links &&
            links.items.map((item) => (
              <Link href="/">
                <a>{item.title}</a>
              </Link>
            ))}
        </nav>
      );
    }
    

    【讨论】:

      猜你喜欢
      • 2016-08-02
      • 2022-12-14
      • 2020-08-16
      • 2018-08-09
      • 1970-01-01
      • 2018-09-03
      • 1970-01-01
      • 2018-04-05
      • 2021-12-07
      相关资源
      最近更新 更多