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

React中useEffect获取API新增数据的问题及无限循环解决

解决方案

核心问题拆解

  • 初始useEffect依赖为空数组,仅在组件挂载时执行一次,新消息添加后不会自动重新拉取数据。
  • 若将loadMessage加入依赖,API返回的数组每次都是新对象引用,React会判定依赖变化,触发无限渲染循环。

具体解决方法

方法1:绑定正确的依赖项(推荐)

把聊天窗口的唯一标识openWindow.chatInfo._id加入useEffect依赖数组,仅当切换聊天窗口时自动加载消息;发送新消息后手动调用刷新函数更新列表:

const ChatWindow = () => {
    const [loadMessage, setLoadMessage] = useState([])
    const [message, setMessage] = useState({ message: "" })

    useEffect(() => {
        loadMessageInChat() 
    }, [openWindow.chatInfo._id]); // 仅聊天ID变化时重新加载

    const loadMessageInChat = async() => {
        try {
           const attempt = await axios.get(`https://bbobras.onrender.com/api/messages/${openWindow.chatInfo._id}`, config)
            if(attempt.status === 200){ 
                setLoadMessage(attempt.data.data)
            }
        } catch (error) {
            console.log(error)
        } 
    }  

    // 发送消息示例函数
    const sendMessage = async () => {
        // 执行发送消息的API调用
        await axios.post(/* 发送接口地址及参数 */)
        // 发送成功后手动刷新消息列表
        loadMessageInChat()
    }
}

export default ChatWindow;

方法2:用useCallback缓存请求函数

如果需要监听消息状态变化(非必要场景不推荐),可以用useCallback包裹请求函数,同时优化状态更新逻辑避免无效重渲染:

import { useCallback, useEffect, useState } from 'react'

const ChatWindow = () => {
    const [loadMessage, setLoadMessage] = useState([])
    const [message, setMessage] = useState({ message: "" })

    // 缓存函数,仅依赖聊天ID和请求配置
    const loadMessageInChat = useCallback(async() => {
        try {
           const attempt = await axios.get(`https://bbobras.onrender.com/api/messages/${openWindow.chatInfo._id}`, config)
            if(attempt.status === 200){ 
                // 对比新旧消息内容,避免无意义的状态更新
                setLoadMessage(prev => {
                    if(JSON.stringify(prev) === JSON.stringify(attempt.data.data)) return prev
                    return attempt.data.data
                })
            }
        } catch (error) {
            console.log(error)
        } 
    }, [config, openWindow.chatInfo._id])

    useEffect(() => {
        loadMessageInChat() 
    }, [loadMessageInChat]); 
}

export default ChatWindow;

方法3:用useRef标记首次加载

通过useRef区分首次加载和后续状态变化,避免无限循环:

import { useEffect, useState, useRef } from 'react'

const ChatWindow = () => {
    const [loadMessage, setLoadMessage] = useState([])
    const [message, setMessage] = useState({ message: "" })
    const isFirstLoad = useRef(true)

    useEffect(() => {
        if(isFirstLoad.current){
            isFirstLoad.current = false
            loadMessageInChat()
        } else {
            // 非首次加载时可自定义逻辑,比如手动触发刷新
        }
    }, [loadMessage]); 

    const loadMessageInChat = async() => {
        try {
           const attempt = await axios.get(`https://bbobras.onrender.com/api/messages/${openWindow.chatInfo._id}`, config)
            if(attempt.status === 200){ 
                setLoadMessage(attempt.data.data)
            }
        } catch (error) {
            console.log(error)
        } 
    }  
}

export default ChatWindow;

总结

最推荐方法1,它贴合React依赖管理逻辑:切换聊天窗口时自动加载历史消息,发送新消息后手动触发刷新,既解决了新消息不显示的问题,又彻底避免无限循环。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 00:41:11