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
相关产品推荐
相关产品推荐

