React中useEffect多次执行导致randomImgNum重复打印的原因及解决方法
问题原因分析
1. console.log多次打印的本质是组件重复渲染
你把console.log(randomImgNum)写在了组件函数顶层,每次调用setRandomImgNum或setRandomTxtNum更新状态时,都会触发组件重新渲染,这个console.log会跟着执行多次,看起来像是useEffect在重复执行,但其实是组件本身在反复渲染。
2. useEffect多次执行的直接原因
- React 18严格模式的调试机制:开发环境下,React 18的严格模式会自动执行两次useEffect(以及其他副作用钩子),用来检测是否存在重复执行会引发问题的副作用,这是开发环境的特殊调试行为,生产环境不会出现。
- 依赖项冗余+逻辑缺陷:你把
setRandomImgNum和setRandomTxtNum放进了依赖数组,但这两个是useState返回的稳定函数,不会随渲染变化;更关键的是,调用setRandomImgNum后立刻用当前randomImgNum判断逻辑,此时randomImgNum还是更新前的旧值,逻辑不符合预期,同时状态更新又触发组件渲染,进一步增加了打印次数。
解决方案
1. 让useEffect仅执行一次的核心操作
将useEffect的依赖数组改为空数组[],这样useEffect只会在组件首次挂载时执行一次。
2. 修正内部逻辑(解决旧状态值问题)
setRandomImgNum是异步操作,调用后randomImgNum不会立刻更新,所以不能直接用当前状态值计算randomTxtNum,应该先算出随机图片编号,再根据这个值直接设置文本编号:
修正后的完整代码:
import React, { useEffect, useState } from "react"; export default function Load() { const [randomImgNum, setRandomImgNum] = useState<number>(1); const [randomTxtNum, setRandomTxtNum] = useState<number>(1); useEffect(() => { // 先计算随机图片编号 const imgNum = Math.floor(Math.random() * 3) + 1; setRandomImgNum(imgNum); const randNum = Math.floor(Math.random() * 100); // 用刚计算的imgNum设置文本编号,而非依赖状态旧值 if (imgNum === 1) { setRandomTxtNum(randNum % 6 + 1); } else if (imgNum === 2) { setRandomTxtNum(randNum % 9 + 1); } else if (imgNum === 3) { setRandomTxtNum(randNum % 5 + 1); } }, []); // 空依赖数组,仅挂载时执行一次 console.log(randomImgNum); // 现在仅在组件挂载和首次状态更新时打印(开发环境严格模式下可能打印两次,生产环境一次) return ( <> </> ); }
额外说明
开发环境下若仍看到useEffect执行两次,属于React 18严格模式的正常调试行为,打包到生产环境后会自动消失,无需额外处理。
内容的提问来源于stack exchange,提问作者minsu123 kim
相关产品推荐
相关产品推荐

