多客户端修改数据时,如何刷新RTK Query的缓存数据?
针对你提到的10人规模ERP系统的缓存同步问题,以下是几个务实的解决方案,按实时性从高到低排序:
1. WebSocket实时推送(推荐用于强实时需求)
在后端添加WebSocket服务,当任意客户端完成资源更新(创建/修改/删除)后,后端主动向所有在线客户端广播更新事件。客户端收到事件后,立即调用RTK Query的缓存失效方法刷新数据。
示例代码(客户端WebSocket监听):
import { useEffect } from 'react'; import { useDispatch } from 'react-redux'; import { api } from './services/api'; function Dashboard() { const dispatch = useDispatch(); useEffect(() => { const socket = new WebSocket('ws://your-api-domain/ws'); socket.onmessage = (event) => { const updateData = JSON.parse(event.data); // 根据后端推送的实体类型,失效对应缓存标签 if (updateData.entityType === 'orders') { dispatch(api.util.invalidateTags(['Orders'])); } else if (updateData.entityType === 'customers') { dispatch(api.util.invalidateTags(['Customers'])); } }; socket.onclose = () => console.log('WebSocket连接关闭'); return () => socket.close(); }, [dispatch]); // ... 组件其余逻辑 }
后端只需在更新接口执行完成后,向WebSocket连接池广播实体更新类型即可(比如用Socket.io简化实现,避免原生WebSocket的兼容问题)。对于10人团队,这个方案的实现成本很低,且能保证数据即时同步。
2. 自动定期重验证(适合弱实时需求)
给RTK Query的查询配置自动重刷新规则,让客户端每隔一段时间主动拉取最新数据,无需后端额外开发。
示例代码(API Slice配置):
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'; export const api = createApi({ baseQuery: fetchBaseQuery({ baseUrl: '/api' }), endpoints: (builder) => ({ getOrders: builder.query({ query: () => '/orders', providesTags: ['Orders'], // 每30秒自动重新获取数据 refetchInterval: 30000, // 组件挂载或查询参数变化时,自动重验证缓存 refetchOnMountOrArgChange: true, }), getCustomers: builder.query({ query: () => '/customers', providesTags: ['Customers'], refetchInterval: 60000, // 每分钟刷新一次客户数据 }), }), });
这个方案不需要后端改动,适合数据更新频率不高的场景。10个用户的请求量完全不会对API造成压力。
3. 手动全局刷新(辅助方案)
在仪表盘添加全局刷新按钮,允许用户主动触发全量或部分实体的缓存失效。同时可以在关键操作(比如提交表单后),自动触发对应实体的刷新。
示例代码(手动刷新逻辑):
import { useDispatch } from 'react-redux'; import { api } from './services/api'; function GlobalRefreshButton() { const dispatch = useDispatch(); const handleRefresh = () => { // 失效所有核心实体的缓存标签 dispatch(api.util.invalidateTags(['Orders', 'Customers', 'Inventory'])); }; return <button onClick={handleRefresh}>刷新所有数据</button>; }
可以把这个按钮放在导航栏显眼位置,作为实时推送方案的 fallback,让用户在需要时主动获取最新数据。
4. 时间戳轮询(轻量替代方案)
如果不想引入WebSocket,可以定期请求后端的一个轻量接口,获取各实体的最新更新时间戳。客户端对比本地存储的时间戳,若不一致则触发对应缓存的失效。
示例代码(时间戳检查逻辑):
import { useEffect } from 'react'; import { useDispatch } from 'react-redux'; import { api } from './services/api'; function UpdateChecker() { const dispatch = useDispatch(); useEffect(() => { const checkUpdates = async () => { const latestTimestamps = await fetch('/api/latest-updates').then(res => res.json()); // 检查订单数据是否更新 const cachedOrderTime = localStorage.getItem('lastOrderUpdate'); if (latestTimestamps.orders !== cachedOrderTime) { dispatch(api.util.invalidateTags(['Orders'])); localStorage.setItem('lastOrderUpdate', latestTimestamps.orders); } // 同理检查其他实体... }; // 每分钟检查一次 const interval = setInterval(checkUpdates, 60000); return () => clearInterval(interval); }, [dispatch]); return null; }
后端的/api/latest-updates接口只需返回各实体的最后更新时间戳(比如从数据库查询最大更新时间),这个方案的带宽消耗极低,适合不想做WebSocket开发的场景。
内容的提问来源于stack exchange,提问作者jgsneves

