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

如何使用React Hooks增量更新状态并批量加载文章

解决React批量加载并实时展示文章的问题

问题分析

你当前代码的核心问题有两个:

  1. 闭包导致状态更新异常:useEffect里的articles始终是初始的空数组,每次setArticles([...articles, ...newArticles])都只会保留最新的100篇,之前的内容会被覆盖;同时判断articles.length === 0永远为true,导致循环只执行一次就停止,无法加载更多内容。
  2. 同步while循环阻塞渲染:即使修复状态问题,同步的while循环会等待所有请求完成后才让组件渲染,无法实现“获取到就立即展示”的需求。

正确实现方案

我们需要改成异步迭代加载,每次请求完成后立即更新状态,让组件实时渲染新内容,同时利用函数式更新获取最新状态,避免闭包问题。

代码实现

import { useState, useEffect } from 'react';
import axios from 'axios';

const ArticleList = () => {
  const [articles, setArticles] = useState([]);
  const [nextArticleNum, setNextArticleNum] = useState(0);
  const [isLoading, setIsLoading] = useState(false);
  const [hasMore, setHasMore] = useState(true);

  // 加载下一批文章的函数
  const loadMoreArticles = async () => {
    if (isLoading || !hasMore) return;
    setIsLoading(true);
    
    try {
      const res = await axios.post("link-to-articles", { nextArticleNum });
      const newArticles = res.data.articles;
      
      // 使用函数式更新获取最新的articles状态
      setArticles(prevArticles => [...prevArticles, ...newArticles]);
      setNextArticleNum(prev => prev + 100);
      
      // 判断是否还有更多文章可加载
      if (newArticles.length < 100) {
        setHasMore(false);
      }
    } catch (err) {
      console.error('加载文章失败:', err);
      // 可根据需求添加错误提示
    } finally {
      setIsLoading(false);
    }
  };

  // 初始加载 + 可选滚动加载
  useEffect(() => {
    loadMoreArticles();
    
    // 滚动到底部自动加载(可选功能)
    const handleScroll = () => {
      const scrollBottom = window.innerHeight + document.documentElement.scrollTop;
      const pageHeight = document.documentElement.offsetHeight;
      if (scrollBottom >= pageHeight - 200 && hasMore && !isLoading) {
        loadMoreArticles();
      }
    };
    
    window.addEventListener('scroll', handleScroll);
    return () => window.removeEventListener('scroll', handleScroll);
  }, []);

  return (
    <div>
      <div className="articles-container">
        {articles.map(article => (
          <div key={article.id} className="article-card">
            <h3>{article.title}</h3>
            <p>{article.content}</p>
          </div>
        ))}
      </div>
      {isLoading && <div>加载中...</div>}
      {!hasMore && !isLoading && <div>已加载全部文章</div>}
    </div>
  );
};

export default ArticleList;

关键改进点

  • 函数式更新状态:setArticles(prevArticles => [...prevArticles, ...newArticles]),确保每次更新都基于最新的状态,彻底解决闭包问题。
  • 拆分加载逻辑:把加载逻辑抽成独立函数,避免同步循环阻塞渲染,每次请求完成后立即更新状态,组件会实时渲染新文章。
  • 状态管理优化:新增isLoading防止重复请求,hasMore判断是否还有更多文章,nextArticleNum记录下一批起始位置,逻辑更清晰。
  • 可选滚动加载:添加滚动监听,实现滚动到底部自动加载更多,提升用户体验。

极简修复版(仅解决原代码问题)

如果不需要滚动加载,只想修复原代码的错误,可以改成这样:

const [articles, setArticles] = useState([]);

useEffect(() => {
  const getArticles = async () => {
    let currentNext = 0;
    let hasMore = true;

    while (hasMore) {
      const articlesRes = await axios.post("link-to-articles", { nextArticleNum: currentNext });
      const newArticles = articlesRes.data.articles;
      
      // 用函数式更新获取最新状态
      setArticles(prev => [...prev, ...newArticles]);
      
      // 根据返回的文章数量判断是否还有更多
      if (newArticles.length < 100) {
        hasMore = false;
      } else {
        currentNext += 100;
      }
      
      // 可选:添加短延迟,避免请求过于频繁
      await new Promise(resolve => setTimeout(resolve, 500));
    }
  };

  getArticles();
}, []);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 18:52:55