如何在React中懒加载Headless UI Dialog并保留过渡效果?
解决React懒加载Headless UI Dialog同时保留过渡效果的方案
核心问题在于直接通过isOpen条件渲染会导致组件立即卸载,打断过渡动画。我们可以通过延迟卸载组件的方式,等过渡完全结束后再移除组件,同时保留懒加载特性。
步骤1:修改Modal组件,暴露过渡结束回调
在Modal组件中,将Headless UI Transition的afterLeave事件暴露给父组件,用于监听过渡完成的时机:
// Modal.js import { Transition, Dialog } from '@headlessui/react'; const Modal = ({ isOpen, onAfterLeave, onClose }) => { return ( <Transition show={isOpen} afterLeave={onAfterLeave} // 传递过渡结束回调 // 保留你的过渡配置,比如时长、动画类名等 className="fixed inset-0 z-50 flex items-center justify-center" > <Dialog as="div" className="relative z-50"> <Dialog.Overlay className="fixed inset-0 bg-black/20" /> <Dialog.Panel className="relative w-full max-w-md p-6 bg-white rounded-lg shadow-xl"> <Dialog.Title className="text-lg font-medium">弹窗标题</Dialog.Title> <button onClick={onClose} className="mt-4 px-3 py-1 bg-gray-200 rounded" > 关闭弹窗 </button> </Dialog.Panel> </Dialog> </Transition> ); }; export default Modal;
步骤2:父组件中管理组件挂载状态
在父组件中,新增一个状态keepModalMounted来控制Modal的挂载,而不是直接用isOpen做条件渲染:
import { lazy, Suspense, useState, useEffect } from 'react'; const Modal = lazy(() => import('~/components/Modal')); function ParentComponent() { const [isOpen, setIsOpen] = useState(false); const [keepModalMounted, setKeepModalMounted] = useState(false); // 当打开弹窗时,确保组件挂载 useEffect(() => { if (isOpen) { setKeepModalMounted(true); } }, [isOpen]); // 过渡结束后,卸载组件 const handleModalAfterLeave = () => { setKeepModalMounted(false); }; return ( <div className="p-4"> <button onClick={() => setIsOpen(true)} className="px-4 py-2 bg-blue-500 text-white rounded" > 打开弹窗 </button> <Suspense fallback={<div className="fixed inset-0 flex items-center justify-center">加载中...</div>}> {/* 用keepModalMounted控制组件挂载,isOpen控制过渡显示 */} {keepModalMounted && ( <Modal isOpen={isOpen} onAfterLeave={handleModalAfterLeave} onClose={() => setIsOpen(false)} /> )} </Suspense> </div> ); }
方案原理
- 首次打开弹窗时,
isOpen变为true,触发useEffect设置keepModalMounted为true,此时懒加载Modal组件,加载完成后执行进入过渡动画。 - 关闭弹窗时,
isOpen变为false,Modal内的Transition开始执行离开过渡,过渡完全结束后调用handleModalAfterLeave,将keepModalMounted设为false,此时才卸载Modal组件,保证过渡动画完整执行。 - 后续再次打开弹窗时,Modal已经被缓存,不会重复触发懒加载,直接显示弹窗。
内容的提问来源于stack exchange,提问作者Javier Villanueva
相关产品推荐
相关产品推荐

