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

React useEffect无依赖变化死循环、空依赖不渲染排查

问题根因说明

你遇到的问题分别对应代码层面的两类错误,和React渲染机制、异步逻辑写法直接相关:

1. 初始版本的无限循环问题

  • 你将状态dates放在了useEffect的依赖数组中,而effect内部执行setDates(values)会直接更新dates状态,触发组件重渲染。重渲染完成后useEffect会对比依赖值,发现dates和上一次渲染的引用不一致,就会再次执行effect逻辑,再次触发setDates,最终形成「执行effect→更新状态→重渲染→再执行effect」的死循环。

2. 空依赖版本不渲染内容的问题

这里有两个独立bug,共同导致了渲染为空的结果:

  • 异步函数写法错误:你定义的getAllFilledJournauxDates存在异步逻辑提前返回的问题。代码中你没有等待getAllJournaux()的Promise执行完成就直接return了dates数组,此时.then里遍历处理日期的逻辑还没执行,返回的永远是空数组。等后续异步请求完成往dates里push值时,函数早就把空值返回给调用方了。
  • 普通变量无法跨渲染周期存值:你在组件顶层定义的let values = []会在每次组件重渲染时被重新初始化为空数组。useEffect里的异步回调给values赋值时,当前渲染周期已经结束,下一次渲染又会把values重置为空,所以你在effect外部打印values永远是空值。
  • 额外说明:你看到useEffect日志打印2次是React 18严格模式下开发环境的预期行为,目的是帮你排查未做清理的副作用,生产环境构建后只会执行1次,不是代码bug。
修复方案

第一步:修复异步数据获取函数

修正异步逻辑,等待接口返回后再处理日期、返回结果,同时修复原有日期格式化里月份少1的问题:

export async function getAllFilledJournauxDates() {
  // 等待接口请求完成再执行后续逻辑
  const response = await getAllJournaux();
  const dates = Object.keys(response).map(element => {
    const rawDate = new Date(response[element].date);
    // 注意getMonth返回0-11,对应实际1-12月,需要+1,补前导零避免格式错乱
    const year = rawDate.getFullYear();
    const month = String(rawDate.getMonth() + 1).padStart(2, '0');
    const day = String(rawDate.getDate()).padStart(2, '0');
    return `${year}-${month}-${day}`;
  })
  return dates;
}

第二步:修复组件逻辑

去掉冗余的顶层values变量,拉取到数据后直接更新状态,空依赖数组保证只在组件首次挂载时拉取一次数据,列表渲染补充必填的key属性:

import { useState, useEffect } from 'react';

export default function Test() {
  const [dates, setDates] = useState([]);
  
  useEffect(() => {
    getAllFilledJournauxDates().then(response => {
      setDates(response);
    });
  }, []);

  return(
    <div>
      {dates.map((date, index) => (
        <div key={index}>{date}</div>
      ))}
    </div>
  );
}
注意事项
  • 不要把effect内部会更新的状态放到依赖数组里,除非你明确需要监听该状态变化重新执行effect,否则会触发无限重渲染。
  • 组件函数每次重渲染都会从头执行所有顶层代码,普通let/const变量会被重新初始化,无法保存跨渲染周期的值,这类持久化数据请存在state或useRef中。
  • 写async函数时,所有依赖异步结果的逻辑都要放在await之后或者.then回调中,避免出现提前返回空值的问题。
  • JS中Date.prototype.getMonth()的返回值范围是0-11,直接使用会比实际月份小1,格式化时记得+1。

内容的提问来源于stack exchange,提问作者AWEMA Agence Web Marketing

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 14:06:30