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

React中useEffect内更新状态后如何正确触发组件重渲染?

你代码存在两个核心问题,对应解决方案如下:

核心问题1:useEffect用法错误 + 异步逻辑未等待

  • 你没有给useEffect传入第二个依赖数组参数,这会导致每次App组件渲染完成后都会反复执行这个useEffect。你在useEffect内修改loading状态会触发组件重渲染,重渲染后又会再次执行useEffect修改loading,自然会形成无限循环。
  • loadResults是异步拉取数据的逻辑,但你现在是同步调用,相当于刚把loading设为true,立刻就执行了设为false的dispatch,React的状态批量更新机制会合并这两次状态变更,最终渲染时只会用最后一次的false状态,这也是你能打印到状态变化但看不到UI更新的原因。

核心问题2:子组件存在冗余状态

子组件不需要额外用useState+useEffect存储按钮文本,直接通过props计算即可,减少不必要的状态监听逻辑。


修正后代码

App组件

import { useReducer, useEffect } from 'react';
import SampleComponent from './SampleComponent';

const App = () => {
  const [state, stateDispatch] = useReducer(stateReducer,{loading: false})
  // 空依赖数组表示仅在组件挂载时执行一次拉取
  // 如果需要依赖特定变量触发拉取(比如搜索词、页码),把对应变量加到依赖数组即可
  useEffect(() => {
    const fetchData = async () => {
      stateDispatch({type:'loadingResults'});
      // 等待异步拉取完成再修改加载状态
      await loadResults();
      stateDispatch({type:'finishedLoadingResults'});
    }
    fetchData();
  }, []); 

  return (
    <SampleComponent loading={state.loading} getBooks={getBooks} />
  );
}

const stateReducer = (prevState,action) => {
    switch(action.type) {
      case 'loadingResults':
        return {...prevState, loading:true};
      case 'finishedLoadingResults':
        return {...prevState, loading: false};
      default:
        throw new Error();
    }
}

子组件

const SampleComponent = (props) => {
  // 直接通过props计算按钮文本,无需额外状态
  const buttonText = props.loading ? 'Loading...' : 'Load More';
  return (
    <div onClick={(event) => props.getBooks(event,false)} className="moreResults">{buttonText}</div>
  )
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 21:15:11