【问题标题】:NextJS useEffect doesn't wait for API responseNextJS useEffect 不等待 API 响应
【发布时间】:2021-11-04 04:41:41
【问题描述】:

第一次加载页面时,我正在努力获取“lovedList”值。重新渲染时,列表会正确更新。我怎样才能让它等待列表值从 useEffect 呈现第一个对象?

import { Post, PostProps } from "./Post";
import { useEffect, useState, useCallback } from "react";
import { api } from "../services/api";
import { useSession } from "next-auth/client";

export function PostList() {
  const [session, status] = useSession();
  const [loading, setLoading] = useState(true);
  const [data, setData] = useState<PostProps[]>([])
  const [skip, setSkip] = useState(0)
  const take = 3

  let list = []

  async function getUserPurchases() {
    if (session) {
      const response = await api.get(`/purchases/${session?.id}`)

      response.data.map(purchase => {
        list.push(purchase.postId)
      })
    }

    return list
  }

  async function handleLoadMore() {
    setLoading(true)
    const lovedList = await getUserPurchases();
    setSkip(skip + take)
    const newPosts = await api.get(`/post?take=${take}&skip=${skip}`)

    const formattedData = newPosts.data.map(post => {
      console.log(lovedList)
      return {
        id: post.id,
        image: post.image,
        institution: post.institution,
        title: post.title,
        description: post.description,
        createdAt: new Date(post.createdAt).toLocaleDateString('pt-BR', {
          day: '2-digit',
          month: 'long',
          year: 'numeric'
        }),
        loved: lovedList.includes(post.id),
        author: {
          image: post.author.image,
          name: post.author.name,
          id: post.author.id
        }
      }
    })

    setData([...data, ...formattedData])
    setLoading(false)
  }

  useEffect(() => {
    handleLoadMore()
  }, [])

  if (loading) {
    return <h1>Carregando</h1>
  }
  return (
    <main className="flex flex-col md:max-w-3xl xl:max-w-6xl mx-auto text-gray-200 text-6xl ">
      {data && data.map(post => (
        <Post
          key={post.id}
          image={post.image}
          institution={post.institution}
          title={post.title}
          description={post.description}
          createdAt={post.createdAt}
          loved={post.loved}
          author={post.author}
          id={post.id}
        />
      ))}

      <button
        type="button"
        className="px-4 py-3 bg-blue-400 rounded-full outline-none flex items-center 
        justify-center text-sm my-16 mx-auto w-4/12 hover:bg-blue-500
        transition-colors duration-200 ease-out"
        onClick={handleLoadMore}
      >
        Carregar Mais
      </button>
    </main>
  );
}

当我加载页面时,console.log 返回空数组。如果接下来的几个项目加载,他们 console.log 属性列表。第一次访问该页面时如何使其正确加载?

谢谢!

【问题讨论】:

    标签: reactjs next.js


    【解决方案1】:

    您可以使用以下任何一种:-

    A.使用你的 loading state
    • 如果loading=false,则仅显示data
      return (
        <main className="flex flex-col md:max-w-3xl xl:max-w-6xl mx-auto text-gray-200 text-6xl ">
          {!loading 
            ? data.map(post => (
              <Post
                key={post.id}
                image={post.image}
                institution={post.institution}
                title={post.title}
                description={post.description}
                createdAt={post.createdAt}
                loved={post.loved}
                author={post.author}
                id={post.id}
              />
            ))
            : 'Loading...'
          }
    
          <button
            type="button"
            className="px-4 py-3 bg-blue-400 rounded-full outline-none flex items-center 
            justify-center text-sm my-16 mx-auto w-4/12 hover:bg-blue-500
            transition-colors duration-200 ease-out"
            onClick={handleLoadMore}
          >
            Carregar Mais
          </button>
        </main>
      );
    
    B.将您的 data state 最初设置为 undefined
    • 当前您将它们设置为const [data, setData] = useState&lt;PostProps[]&gt;([])
    • 将其更改为undefined、const [data, setData] = useState&lt;PostProps[]&gt;()。 我不确定你是否可以这样做。我以前从来没有用过这个useState&lt;Props&gt;([])syntax
    • 那么您当前的条件 data &amp;&amp; data.map(post =&gt; (... 将按预期工作。
    • 之前它不起作用,因为最初将 data 设置为 []/空数组。

    【讨论】:

    • 这两种解决方案都毫无意义。例如,加载状态不会影响数据检索,因此与页面一起加载的第一个将不可用。因此,组件不会重新加载。至于 B,该语法意味着 Typescript,它只是类型。我不能设置为 undefined 否则将无法遍历列表,因为 undefined 是不可迭代的。
    【解决方案2】:

    非常感谢 Rockeseat 的 Joseph 提供的解决方案!

    基本上,如果我想在页面加载时准备好列表,我需要使用服务器端渲染。这意味着我必须在使用该组件的页面中使用 Next 中的 ServerSideProps。

    【讨论】:

      【解决方案3】:

      要验证数据数组,您应该验证长度,因为“数据”常量已经存在:

      data.lenght > 0
      

      除此之外,您还可以向对象“?”添加阻止:

      post?.id
      

      最终代码:

      import { Post, PostProps } from "./Post";
      import { useEffect, useState, useCallback } from "react";
      import { api } from "../services/api";
      import { useSession } from "next-auth/client";
      
      export function PostList() {
        const [session, status] = useSession();
        const [loading, setLoading] = useState(true);
        const [data, setData] = useState<PostProps[]>([])
        const [skip, setSkip] = useState(0)
        const take = 3
      
        let list = []
      
        async function getUserPurchases() {
          if (session) {
            const response = await api.get(`/purchases/${session?.id}`)
      
            response.data.map(purchase => {
              list.push(purchase.postId)
            })
          }
      
          return list
        }
      
        async function handleLoadMore() {
          setLoading(true)
          const lovedList = await getUserPurchases();
          setSkip(skip + take)
          const newPosts = await api.get(`/post?take=${take}&skip=${skip}`)
      
          const formattedData = newPosts.data.map(post => {
            console.log(lovedList)
            return {
              id: post.id,
              image: post.image,
              institution: post.institution,
              title: post.title,
              description: post.description,
              createdAt: new Date(post.createdAt).toLocaleDateString('pt-BR', {
                day: '2-digit',
                month: 'long',
                year: 'numeric'
              }),
              loved: lovedList.includes(post.id),
              author: {
                image: post.author.image,
                name: post.author.name,
                id: post.author.id
              }
            }
          })
      
          setData([...data, ...formattedData])
          setLoading(false)
        }
      
        useEffect(() => {
          handleLoadMore()
        }, [])
      
        if (loading || data?.lenght === 0) {
          return <h1>Carregando</h1>
        }
        return (
          <main className="flex flex-col md:max-w-3xl xl:max-w-6xl mx-auto text-gray-200 text-6xl ">
            {data?.length > 0 && data?.map(post => (
              <Post
                key={post?.id}
                image={post?.image}
                institution={post?.institution}
                title={post?.title}
                description={post?.description}
                createdAt={post?.createdAt}
                loved={post?.loved}
                author={post?.author}
                id={post?.id}
              />
            ))}
      
            <button
              type="button"
              className="px-4 py-3 bg-blue-400 rounded-full outline-none flex items-center 
              justify-center text-sm my-16 mx-auto w-4/12 hover:bg-blue-500
              transition-colors duration-200 ease-out"
              onClick={handleLoadMore}
            >
              Carregar Mais
            </button>
          </main>
        );
      }

      【讨论】:

        猜你喜欢
        • 2020-12-03
        • 2012-09-08
        • 1970-01-01
        • 2017-01-28
        • 1970-01-01
        • 2021-03-21
        • 2017-07-21
        • 2018-08-04
        • 2022-07-01
        相关资源
        最近更新 更多