React实现无刷新实时展示MongoDB更新数据的方案咨询
可行的实时数据同步方案
针对你的需求,这里提供几个无需复杂WebSocket实现的方案,适配MongoDB+Node.js+React的技术栈,从易到难选择:
方案1:长轮询(Long Polling)
对普通轮询的优化,后端会挂起请求直到数据库有更新或超时,避免前端频繁发起无效请求。
后端实现(Node.js + Express + Mongoose)
const ReceptionQueue = require('./models/ReceptionQueue'); let lastUpdateTime = new Date(); app.get('/main-table/receptionQueue', async (req, res) => { // 设置30秒超时,超时后返回空响应触发前端重连 const timeout = setTimeout(() => { res.status(204).send(); }, 30000); // 监听MongoDB集合变化 const changeStream = ReceptionQueue.watch(); changeStream.on('change', async () => { clearTimeout(timeout); changeStream.close(); // 查询最新数据并返回 const latestData = await ReceptionQueue.find(); lastUpdateTime = new Date(); res.json(latestData); }); // 初始化检查:如果已有更新数据直接返回 const latestRecord = await ReceptionQueue.findOne().sort({updatedAt: -1}); if (latestRecord && latestRecord.updatedAt > lastUpdateTime) { clearTimeout(timeout); changeStream.close(); lastUpdateTime = latestRecord.updatedAt; res.json(await ReceptionQueue.find()); } });
前端React实现
useEffect(() => { let isMounted = true; const fetchQueue = async () => { if (!isMounted) return; try { const response = await axios.get('http://localhost:3001/main-table/receptionQueue'); if (response.status === 200) { setQueue(response.data); } // 请求完成后立即发起下一次长轮询 fetchQueue(); } catch (error) { console.error('Error fetching reception queue data:', error); // 出错后延迟5秒重试,避免频繁报错 setTimeout(fetchQueue, 5000); } }; fetchQueue(); // 组件卸载时终止请求 return () => { isMounted = false; }; }, []);
方案2:Server-Sent Events (SSE)
基于HTTP的单向实时通信协议,后端可主动向客户端推送数据,实现比WebSocket简单得多,无需处理双向连接。
后端实现(Node.js + Express + Mongoose)
app.get('/main-table/receptionQueue/sse', async (req, res) => { // 设置SSE专属响应头 res.setHeader('Content-Type', 'text/event-stream'); res.setHeader('Cache-Control', 'no-cache'); res.setHeader('Connection', 'keep-alive'); // 推送初始数据 const initialData = await ReceptionQueue.find(); res.write(`data: ${JSON.stringify(initialData)}\n\n`); // 监听MongoDB集合变化,有更新就推送最新数据 const changeStream = ReceptionQueue.watch(); changeStream.on('change', async () => { const latestData = await ReceptionQueue.find(); res.write(`data: ${JSON.stringify(latestData)}\n\n`); }); // 客户端断开连接时清理资源 req.on('close', () => { changeStream.close(); res.end(); }); });
前端React实现
useEffect(() => { const eventSource = new EventSource('http://localhost:3001/main-table/receptionQueue/sse'); // 接收后端推送的数据 eventSource.onmessage = (event) => { const data = JSON.parse(event.data); setQueue(data); }; // 处理连接错误,自动重试 eventSource.onerror = (error) => { console.error('SSE connection error:', error); eventSource.close(); setTimeout(() => { window.location.reload(); // 或重新创建EventSource实例 }, 5000); }; // 组件卸载时关闭SSE连接 return () => { eventSource.close(); }; }, []);
方案3:MongoDB Change Streams + 批量客户端通知
精准监听MongoDB集合的增删改操作,后端捕获到变化后,主动推送给所有连接的前端客户端,是最高效的方案。
后端核心代码
const ReceptionQueue = require('./models/ReceptionQueue'); let connectedClients = []; // 存储所有活跃的SSE客户端连接 // 服务启动时监听集合变化 const changeStream = ReceptionQueue.watch(); changeStream.on('change', async () => { const latestData = await ReceptionQueue.find(); // 给所有连接的客户端推送最新数据 connectedClients.forEach(client => { client.write(`data: ${JSON.stringify(latestData)}\n\n`); }); }); // SSE连接接口,维护客户端列表 app.get('/main-table/receptionQueue/sse', async (req, res) => { res.setHeader('Content-Type', 'text/event-stream'); res.setHeader('Cache-Control', 'no-cache'); res.setHeader('Connection', 'keep-alive'); connectedClients.push(res); // 推送初始数据 const initialData = await ReceptionQueue.find(); res.write(`data: ${JSON.stringify(initialData)}\n\n`); // 客户端断开时移除连接 req.on('close', () => { connectedClients = connectedClients.filter(client => client !== res); res.end(); }); });
前端实现与方案2的SSE前端代码完全一致。
内容的提问来源于stack exchange,提问作者m_c
相关产品推荐
相关产品推荐

