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

React中useEffect setState后console.log多次输出原因咨询

问题描述

我通过axios的fetchData('/content')从MongoDB获取数据,将数据存入新数组后调用setTexts更新state。功能正常实现,但console.log(texts)会输出两次(React严格模式下四次);若不使用forEach,仅输出一次(严格模式下两次)。尝试用map替代forEach、调整代码位置均无效,作为React新手,想了解该现象的原因。

相关代码:

const [texts, setTexts] = useState('')

useEffect(() => {
    const getText = async () => {
        const datas = await fetchData("/content")
        const values = []
        datas.data.forEach(text => {
            values[text.name] = text.tex_fr || text.items
        });

        setTexts(values)
    }
    getText()
}, [])

console.log(texts)
原因解析

首先明确:React组件每渲染一次,就会执行一次console.log(texts),所以输出次数等于组件渲染次数。

核心问题:用数组存储非索引键的属性

你初始化values为数组[],但通过values[text.name] = ...给它添加字符串类型的键——JS里允许这么做,但数组的设计初衷是存储按索引排列的有序数据,你这种用法本质是把数组当成普通对象在用。

当调用setTexts(values)时,React会做浅比较来判断是否需要更新组件:

  • 若不用forEach,直接给values赋值普通对象/正常数组,React能准确识别状态变化,触发一次更新。
  • 但你用数组存非索引键时,数组的length属性没变化(你没通过push等方法添加元素),React第一次浅比较可能认为状态没变化;但你确实修改了数组的属性,后续又会判定状态变化,导致额外的一次渲染,最终输出两次。

严格模式的放大作用

React严格模式会重复执行渲染、副作用逻辑(比如useEffect里的代码会跑两次),目的是提前暴露潜在问题。所以正常模式下两次输出,严格模式下会变成四次,这是严格模式的正常行为。

修复方案

把values的初始化改成对象{},因为你用字符串作为键存储数据,对象才是匹配的数据结构:

const [texts, setTexts] = useState({}) // 同时把初始state从''改成{}更合理

useEffect(() => {
    const getText = async () => {
        const datas = await fetchData("/content")
        const values = {} // 从[]改为{}
        datas.data.forEach(text => {
            values[text.name] = text.tex_fr || text.items
        });

        setTexts(values)
    }
    getText()
}, [])

console.log(texts)

修改后React能正确识别状态变化,渲染次数会回到正常的两次(严格模式下四次,属于预期行为)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 11:03:27