React MUI Snackbar组件求助:多消息依次显示功能异常修复
解决NextJS+MUI+Easy-Peasy多Snackbar顺序显示问题
问题根源
核心问题是没实现消息队列的逐个消费逻辑:之前的代码可能同时渲染所有消息,或仅监听了数组初始变化,导致只有第一条消息触发了关闭定时器,后续消息因从未进入"活跃显示"状态,无法触发自动关闭。
解决方案
维护一个消息队列,每次仅显示队列头部的消息,当前消息关闭(超时或手动)后从队列移除,自动触发下一条消息的显示。
1. 配置Easy-Peasy状态管理
在store中定义消息队列状态及添加/移除action,为每个消息生成唯一ID用于追踪:
// store.js import { createStore, action } from 'easy-peasy'; const store = createStore({ snackbarQueue: [], // 添加消息到队列 addSnackbar: action((state, payload) => { state.snackbarQueue.push({ id: Date.now(), // 用时间戳生成唯一ID ...payload, }); }), // 根据ID移除消息 removeSnackbar: action((state, id) => { state.snackbarQueue = state.snackbarQueue.filter(snack => snack.id !== id); }), }); export default store;
2. 实现Snackbar队列组件
组件仅渲染队列的第一条消息,通过useEffect监听当前活跃消息,设置4秒超时自动移除,移除后队列下一条消息自动顶上来:
// components/SnackbarQueue.js import { useEffect } from 'react'; import { Snackbar, Alert } from '@mui/material'; import { useStoreActions, useStoreState } from 'easy-peasy'; const SnackbarQueue = () => { const snackbarQueue = useStoreState(state => state.snackbarQueue); const removeSnackbar = useStoreActions(actions => actions.removeSnackbar); // 当前仅显示队列的第一个消息 const currentSnack = snackbarQueue[0]; // 监听当前消息变化,设置自动关闭定时器 useEffect(() => { let timer; if (currentSnack) { timer = setTimeout(() => { removeSnackbar(currentSnack.id); }, 4000); } // 组件卸载或当前消息变化时清除定时器 return () => clearTimeout(timer); }, [currentSnack, removeSnackbar]); // 手动关闭逻辑 const handleClose = (event, reason) => { if (reason === 'clickaway') return; removeSnackbar(currentSnack.id); }; return ( <Snackbar open={!!currentSnack} autoHideDuration={null} // 禁用MUI自带的自动隐藏,用手动定时器控制 onClose={handleClose} anchorOrigin={{ vertical: 'bottom', horizontal: 'center' }} > {currentSnack && ( <Alert severity={currentSnack.severity || 'info'} onClose={handleClose} > {currentSnack.message} </Alert> )} </Snackbar> ); }; export default SnackbarQueue;
3. 使用组件触发多消息
在需要触发Snackbar的地方调用addSnackbar方法添加消息到队列即可:
// 示例组件 import { useStoreActions } from 'easy-peasy'; const DemoComponent = () => { const addSnackbar = useStoreActions(actions => actions.addSnackbar); const triggerMultipleSnacks = () => { addSnackbar({ message: '操作成功!', severity: 'success' }); addSnackbar({ message: '请注意查看后续通知', severity: 'info' }); addSnackbar({ message: '当前存储空间不足', severity: 'warning' }); }; return ( <button onClick={triggerMultipleSnacks}> 触发多条消息 </button> ); };
关键注意点
- 唯一ID:每个消息必须有唯一标识,避免移除时误删其他消息
- 禁用MUI自动隐藏:避免自带的
autoHideDuration和自定义定时器逻辑冲突 - 队列消费逻辑:始终只处理队列头部元素,确保消息按顺序逐个显示
内容的提问来源于stack exchange,提问作者aabdulahad
相关产品推荐
相关产品推荐

