You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NextJS中useEffect未等待API响应 首次加载lovedList为空如何解决

问题原因

  • 核心是useSession的加载时序问题:next-auth的useSession在组件首次挂载时还未完成鉴权校验,此时session值为null,首次执行getUserPurchases时直接跳过了接口请求逻辑,返回空数组。
  • 原useEffect只在组件首次挂载时触发一次,没有监听session的加载状态,等到session加载完成后不会重新触发数据拉取逻辑。
  • 组件外部声明的list全局变量存在闭包风险,多次调用可能累积脏数据。

修复方案

  1. 新增判断:只有session加载完成(status !== 'loading')之后才执行数据拉取逻辑
  2. 调整useEffect依赖数组,加入session和status作为依赖,保证session加载完成后自动触发首次数据拉取
  3. 移除全局的list变量,直接在getUserPurchases内部处理并返回结果,避免闭包问题
  4. 用useCallback包裹handleLoadMore,补全依赖,避免重复渲染导致的函数重复创建
  5. 状态更新改用函数式写法,避免闭包拿到旧的状态值

修改后代码

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

  async function getUserPurchases() {
    if (!session) return []
    const response = await api.get(`/purchases/${session.id}`)
    // 直接返回处理后的数组,不用外部变量存储
    return response.data.map(purchase => purchase.postId)
  }

  // 用useCallback包裹,补全所有依赖
  const handleLoadMore = useCallback(async () => {
    // session还在加载时直接返回,不执行后续逻辑
    if (status === 'loading') return
    setLoading(true)
    const lovedList = await getUserPurchases();
    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(prev => [...prev, ...formattedData])
    setSkip(prev => prev + take)
    setLoading(false)
  }, [session, status, skip, take])

  // 调整useEffect依赖,session加载完成且无数据时自动触发首次加载
  useEffect(() => {
    if (status !== 'loading' && data.length === 0) {
      handleLoadMore()
    }
  }, [status, session, data.length, 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>
  );
}

内容的提问来源于stack exchange,提问作者Vitor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 17:45:02