将RTK Query结果存入useState触发无限循环报错
解决RTK Query数据存入useState导致的无限重渲染问题
你遇到的Maximum update depth exceeded警告,根源是RTK Query每次返回的notifications数组都是新的引用(即使内容完全不变),导致依赖该数组的useEffect反复执行setNotificationList,触发组件重新渲染,进而再次获取新引用的数组,形成无限循环。
下面提供两种解决方案,优先推荐方案一(符合RTK Query的设计理念):
方案一:使用RTK Query的updateQueryData直接修改缓存(推荐)
RTK Query内置了修改缓存的能力,无需额外维护本地state,既能保证和服务器数据的同步,又能处理本地操作(比如删除通知)。
修改步骤:
- 移除本地的
notificationListstate和对应的useEffect - 从
useGetUserNotificationsQuery中解构出updateQueryData方法 - 在删除逻辑中调用
updateQueryData直接修改缓存
修改后的核心代码:
// 获取查询数据和缓存更新方法 const { data: notifications = [], isLoading, isError, updateQueryData } = useGetUserNotificationsQuery(); // 处理删除通知 const handleDeleteNotification = () => { // 使用Immer语法修改缓存的draft对象 updateQueryData('getUserNotifications', undefined, (draft) => { const targetIndex = draft.findIndex(n => n._id === selectedNotification._id); if (targetIndex !== -1) { draft.splice(targetIndex, 1); } }); handleMenuClose(); };
完整组件修改示例(关键部分):
const NotificationList = () => { const [anchorEl, setAnchorEl] = useState(null); const [selectedNotification, setSelectedNotification] = useState(null); // 解构出updateQueryData方法 const { data: notifications = [], isLoading, isError, updateQueryData } = useGetUserNotificationsQuery(); const [userNotificationRead] = useUserNotificationReadMutation(); // ...其他方法(handleMenuOpen、handleMenuClose等)保持不变 const handleDeleteNotification = () => { // 直接更新RTK Query缓存 updateQueryData('getUserNotifications', undefined, (draft) => { const index = draft.findIndex( notification => notification._id === selectedNotification._id ); if (index !== -1) { draft.splice(index, 1); } }); handleMenuClose(); }; // ...加载状态判断保持不变 // 空状态判断改用notifications if(!notifications.length) { // ...原空状态代码,保持不变 } // 渲染时直接使用notifications数组 return ( <div> {notifications.map((notification) => ( // ...原渲染逻辑,保持不变 ))} {/* ...菜单代码,保持不变 */} </div> ); };
方案二:保留本地state,避免不必要更新
如果必须维护本地state,需要在useEffect中判断数组内容是否真的变化,再执行更新:
方法1:内容比较后更新
useEffect(() => { // 简单比较数组内容(适合结构简单的对象),不同时才更新 const contentChanged = JSON.stringify(notifications) !== JSON.stringify(notificationList); if (contentChanged) { setNotificationList(notifications); } }, [notifications, notificationList]);
注意:如果通知对象包含日期、函数等复杂类型,JSON.stringify会失效,此时可以使用深比较工具(如lodash的isEqual)。
方法2:用useMemo缓存稳定的数组引用
// 基于内容生成稳定的引用 const stableNotifications = useMemo(() => notifications, [JSON.stringify(notifications)]); useEffect(() => { setNotificationList(stableNotifications); }, [stableNotifications]);
内容的提问来源于stack exchange,提问作者pkpk
相关产品推荐
相关产品推荐

