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

React中如何等待useState计数器更新完成后执行后续逻辑

问题根因

React的useState状态更新是异步批量执行的:调用setCount/setPage后不会立刻修改当前作用域下的状态变量,而是会将更新请求加入调度队列,等当前同步代码全部执行完成后再统一更新状态、触发组件重渲染。你原有代码中用Promise包裹setCount后立刻resolve,本质上还是同步执行逻辑,根本等不到状态更新完成,后续调用updateNews拿到的始终是更新前的旧状态值。

解决方案

有两种成熟的实现方式适配你的需求:

方案1:直接传递新值给业务方法

不用等待状态更新完成,计算出新的计数后直接传给updateNews使用,状态更新和业务逻辑执行互不阻塞:

const fetchMoreData = async () => {
  const newCount = count + 1;
  setCount(newCount);
  // 直接将新值传入updateNews,避免依赖旧的状态闭包
  updateNews(newCount);
};

方案2:用useEffect监听状态变化

将updateNews的触发和状态更新绑定,状态变更后自动触发业务逻辑,保证拿到的永远是最新的状态值:

const fetchMoreData = () => {
  // 用函数式更新避免闭包导致的状态计算错误
  setCount(prev => prev + 1);
};

// 监听count变化,count更新后自动执行updateNews
useEffect(() => {
  // 可根据业务需求加判断,避免初始化时多余执行
  if (count > 1) {
    updateNews();
  }
}, [count]);

适配你的新闻业务场景的修正代码

针对你提供的完整业务代码,推荐用方案2实现,修正后的核心逻辑如下:

import React, { useEffect, useState } from "react";
import NewsItem from "./NewsItem";
import Spinner from "./Spinner";
import PropTypes from "prop-types";
import InfiniteScroll from "react-infinite-scroll-component";

const News = (props) => {
  const [articles, setArticles] = useState([]);
  const [loading, setLoading] = useState(true);
  const [page, setPage] = useState(1);
  const [totalResults, setTotalResults] = useState(0);

  const capitalizeFirstLetter = (string) => {
    return string.charAt(0).toUpperCase() + string.slice(1);
  };

  // updateNews直接使用最新的page状态
  const updateNews = async () => {
    props.setProgress(10);
    const url = `newsapi.org/v2/…${props.country}&category=${props.category}&apiKey=${props.apiKey}&page=${page}&pageSize=${props.pageSize}`;
    props.setProgress(30);
    let data = await fetch(url);
    props.setProgress(50);
    let parsedData = await data.json();
    props.setProgress(70);
    if (parsedData) {
      // 用函数式更新articles,避免闭包导致的旧数组拼接问题
      setArticles(prevArticles => prevArticles.concat(parsedData.articles));
      setLoading(false);
      setTotalResults(parsedData.totalResults);
    }
    props.setProgress(100);
  };

  // 初始化加载第一页
  useEffect(() => {
    updateNews();
    // eslint-disable-next-line
  }, []);

  // 监听page变化,自动加载对应页数据
  useEffect(() => {
    // 跳过第一页的重复执行
    if (page > 1) {
      updateNews();
    }
  }, [page]);

  const fetchMoreData = () => {
    // 只负责更新page,后续逻辑交给监听useEffect处理
    setPage(prevPage => prevPage + 1);
  };
  
  return (
    <>
      <h3 className="text-center" style={{ marginTop: "4%" }}>
        NewsMonkey - Top `${capitalizeFirstLetter(props.category)}` Headlines
      </h3>
      {loading && <Spinner />}
      <InfiniteScroll
        dataLength={articles.length}
        next={fetchMoreData}
        hasMore={articles.length < totalResults}
        loader={<Spinner />}
      >
        <div className="container">
          <div className="row">
            {articles.map((element) => {
              return (
                <div className="col-md-4" key={element.url}>
                  <NewsItem
                    title={
                      element && element.title ? element.title.slice(0, 45) : ""
                    }
                    description={
                      element && element.description
                        ? element.description.slice(0, 50)
                        : ""
                    }
                    imageUrl={element.urlToImage}
                    newsUrl={element.url}
                    author={element.author}
                    date={element.publishedAt}
                    source={element.source.name}
                  />
                </div>
              );
            })}
          </div>
        </div>
      </InfiniteScroll>
    </>
  );
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 16:39:04