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

在useEffect Hook中设置状态异常:无法存入对象数组至postMItems

React状态postMItems无法正确填充数组的问题解决

我需要将React状态postMItems设置为对象数组,现有代码能通过接口获取的数据正确填充临时数组existingM,但无法将相同数据存入postMItems状态。原代码如下:

const [postMItems, setPostMItems] = useState([]);

let existingM = []

useEffect(() => {
    const fetchMItems = async () => {

        const endpoint = `http://${process.env.NEXT_PUBLIC_HOST}:1337/api/manufactureds?fields[0]=title&sort=id:ASC&populate[image][fields][0]=name&populate[image][fields][1]=url`
        const options = {
            method: 'GET',
            headers: {
                'Authorization': `Bearer ${process.env.NEXT_PUBLIC_API_TOKEN}`
            }
        }

        const response = await fetch(endpoint, options)
        const data = await response.json();
        console.log(data);


        for (let i = 0; i < data.data.length; i++) {
            let mID = data.data[i].id
            let mName = data.data[i].attributes.title
            let mImage = data.data[i].attributes.image.data ? data.data[i].attributes.image.data.attributes.url : ''


            setPostMItems([
                ...postMItems,
                {
                    mID: mID,
                    mName: mName,
                    mImage: mImage
                }
                ]
                )
                console.log(postMItems);

            existingM.push(
                {
                    mID: mID,
                    mName: mName,
                    mImage: mImage
                }
            )

        }

        console.log(existingM)
        console.log(postMItems)
    }

    fetchMItems();

}, []);

问题原因

  • React状态更新是异步的,加上useEffect依赖为空数组,循环中每次调用setPostMItems时,引用的postMItems都是初始的空数组(闭包捕获了组件首次渲染时的状态),最终状态只会保留最后一次添加的元素。
  • 循环内多次触发状态更新会导致组件重复重渲染,既影响性能也容易引发逻辑问题。

解决方案

直接将接口返回的数据处理成完整的目标数组,再一次性设置状态,这是最可靠高效的方式:

const [postMItems, setPostMItems] = useState([]);

useEffect(() => {
    const fetchMItems = async () => {
        const endpoint = `http://${process.env.NEXT_PUBLIC_HOST}:1337/api/manufactureds?fields[0]=title&sort=id:ASC&populate[image][fields][0]=name&populate[image][fields][1]=url`;
        const options = {
            method: 'GET',
            headers: {
                'Authorization': `Bearer ${process.env.NEXT_PUBLIC_API_TOKEN}`
            }
        };

        const response = await fetch(endpoint, options);
        const data = await response.json();
        
        // 用map遍历数据,直接生成目标数组
        const newPostMItems = data.data.map(item => {
            const mID = item.id;
            const mName = item.attributes.title;
            const mImage = item.attributes.image.data ? item.attributes.image.data.attributes.url : '';
            return { mID, mName, mImage };
        });
        
        // 一次性更新状态
        setPostMItems(newPostMItems);
        
        console.log(newPostMItems); // 此时数组内容和原代码的existingM完全一致
    };

    fetchMItems();
}, []);

另一种可选方式(不推荐用于此场景)

如果特殊场景下需要在循环中更新状态,可以使用函数式更新,它会接收当前最新的状态作为参数,确保每次更新都基于最新值:

// 仅作示例,推荐使用上面的一次性更新方式
for (let i = 0; i < data.data.length; i++) {
    const mID = data.data[i].id;
    const mName = data.data[i].attributes.title;
    const mImage = data.data[i].attributes.image.data ? data.data[i].attributes.image.data.attributes.url : '';
    
    setPostMItems(prevState => [...prevState, { mID, mName, mImage }]);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 14:18:29