Material UI Transition搭配Snackbar使用时onExited事件不触发问题
问题原因
这个问题在Material UI的Snackbar组件使用中非常常见,核心是两个错误用法导致的:
- 你把
slideTransition定义在父组件的渲染逻辑内部,每次父组件重渲染时这个函数组件的引用都会更新,React会把它判定为全新的组件,直接销毁旧实例、创建新实例,退出动画的生命周期直接被中断,onExited自然没有触发机会。 - 你给
Slide组件绑定回调的逻辑会覆盖Snackbar的内置回调:你先展开了Snackbar传递给Transition组件的props,再自定义onEntered和onExited,这会直接覆盖Snackbar内部依赖的过渡生命周期回调,导致Snackbar的退出流程逻辑异常。
修复方案
- 把
slideTransition移到父组件外部定义,避免每次渲染生成新的组件引用,如果需要用到父组件内部的回调,可以通过props传递:
// 移到组件外部定义 const slideTransition = (props) => { // 先执行Snackbar内置回调,再执行自定义逻辑,避免打断内置流程 const handleEntered = () => { props.onEntered?.(); props.customOnTransition?.(); }; const handleExited = () => { props.onExited?.(); props.customOnTransition?.(); }; return <Slide {...props} direction='right' onEntered={handleEntered} onExited={handleExited} />; }; // 父组件内使用时传入自定义回调 return ( <div> <Snackbar open={open} autoHideDuration={3000} onClose={handleClose} TransitionComponent={slideTransition} TransitionProps={{ customOnTransition: handleExited }} > <div> <AlertWrapper severity={snackbarVar()[0]?.severity}> {snackbarVar()[0]?.message} </AlertWrapper> </div> </Snackbar> </div> );
- 如果不想把组件移到外部,也可以用
useCallback包裹slideTransition的定义,保证引用稳定:
const slideTransition = useCallback((props) => { const handleEntered = () => { props.onEntered?.(); handleExited(); }; const handleExitedCb = () => { props.onExited?.(); handleExited(); }; return <Slide {...props} direction='right' onEntered={handleEntered} onExited={handleExitedCb} />; }, [handleExited]);
另外需要注意不要在Snackbar过渡过程中直接卸载组件,要通过open属性控制组件的展示隐藏,等过渡完成后再做数据清理逻辑。
内容的提问来源于stack exchange,提问作者Peter Boomsma
相关产品推荐
相关产品推荐

