You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 13:35:20