【@ebay/nice-modal-react】管理React弹窗(Modal)状态

文章目录

简单来说,这个库让你像调用函数一样打开一个弹窗,并且这个弹窗的逻辑可以独立编写和复用,非常适合管理大型应用中的复杂弹窗交互

一、使用流程

1.1、安装

bash 复制代码
npm install @ebay/nice-modal-react
# 或
yarn add @ebay/nice-modal-react

1.2、创建

js 复制代码
// MyAntdModal.js
import { Modal } from 'antd';
import NiceModal, { useModal } from '@ebay/nice-modal-react';

// 使用 NiceModal.create 创建高阶组件
const MyAntdModal = NiceModal.create(({ title, content }) => {
  // useModal 钩子提供了控制当前弹窗的方法和状态
  const modal = useModal();

  const handleOk = () => {
    // 你自己的逻辑...
    modal.hide(); // 隐藏弹窗
  };

  return (
    <Modal
      title={title}
      open={modal.visible} // 绑定visible状态
      onOk={handleOk}
      onCancel={() => modal.hide()} // 点击取消同样隐藏
      afterClose={() => modal.remove()} // 关闭动画结束后,从DOM移除
    >
      <p>{content}</p>
    </Modal>
  );
});

export default MyAntdModal;

为 Ant Design 等提供了快捷绑定方法

js 复制代码
// MyAntdModal.js
import { Modal } from 'antd';
import NiceModal, { useModal, antdModal } from '@ebay/nice-modal-react';

// 使用 NiceModal.create 创建高阶组件
const MyAntdModal = NiceModal.create(({ title, content }) => {
  // useModal 钩子提供了控制当前弹窗的方法和状态
  const modal = useModal();

  const handleOk = () => {
    // 你自己的逻辑...
    modal.hide(); // 隐藏弹窗
  };

  return (
    <Modal
      title={title}
      {...antdModal(modal)}
    >
      <p>{content}</p>
    </Modal>
  );
});

export default MyAntdModal;

1.3、使用

  1. 首先,你必须在应用根组件外用 NiceModal.Provider 包裹你的应用
js 复制代码
// index.js 或 App.js
import React from 'react';
import ReactDOM from 'react-dom';
import NiceModal from '@ebay/nice-modal-react';
import App from './App';

ReactDOM.render(
  <React.StrictMode>
    <NiceModal.Provider> {/* 全局状态提供者 */}
      <App />
    </NiceModal.Provider>
  </React.StrictMode>,
  document.getElementById('root')
);
  1. 之后,你就可以在任意子组件中,像调用函数一样展示这个弹窗
js 复制代码
// SomeComponent.js
import NiceModal from '@ebay/nice-modal-react';
import MyAntdModal from './MyAntdModal';

function SomeComponent() {
  const showModal = () => {
    // 关键:指令式调用,直接传递props
    NiceModal.show(MyAntdModal, { 
      title: '你好', 
      content: '这是一个优雅的弹窗示例。' 
    });
  };

  return <button onClick={showModal}>打开弹窗</button>;
}

二、通过ID注册

使用ID注册:适合大型项目,你希望将弹窗作为全局服务管理,调用方与具体组件解耦,便于维护和重构。

使用组件引用:适合简单场景或局部使用,代码更直接,无需维护一个中央注册文件。

通过NiceModal.register('modal-id', MyModal)给弹窗注册一个ID,之后就可以通过ID来调用(NiceModal.show('modal-id')),方便在大型项目中统一管理所有弹窗。

  1. 创建弹窗组件
js 复制代码
/* 创建弹窗组件 */
// UserInfoModal.jsx
import { Modal } from 'antd';
import NiceModal, { useModal, antdModal } from '@ebay/nice-modal-react';

const UserInfoModal = NiceModal.create(({ userId }) => {
  const modal = useModal();

  // 在这里,你可以根据传入的 userId 发起请求,获取用户详情
  // const [userInfo, setUserInfo] = useState(null);

  return (
    <Modal
      title="用户详情"
      {...antdModal(modal)}
    >
      <p>这里是用户 ID 为 {userId} 的详细信息。</p>
    </Modal>
  );
});

export default UserInfoModal;
  1. 注册弹窗(关键步骤)
js 复制代码
/* 注册弹窗(关键步骤) */
// modals.js  (建议创建一个专门的注册文件)
import NiceModal from '@ebay/nice-modal-react';
import UserInfoModal from './UserInfoModal';

// 为弹窗注册一个ID,ID在整个应用中应保持唯一
NiceModal.register('user_info_modal', UserInfoModal);

// 你可以在这里注册项目中所有的弹窗
// NiceModal.register('another_modal', AnotherModal);
  1. 在入口文件中导入该文件
js 复制代码
/* 在入口文件中导入该文件 */
// src/index.jsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import NiceModal from '@ebay/nice-modal-react';
import App from './App';
import './modals/modals.js'; // ⭐核心:导入注册文件,执行内部注册语句

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <NiceModal.Provider> {/* 确保 Provider 包裹应用 */}
      <App />
    </NiceModal.Provider>
  </React.StrictMode>
);
  1. 在组件中通过 ID 调用弹窗
js 复制代码
/* 在组件中通过 ID 调用弹窗 */
// SomeComponent.jsx
import NiceModal from '@ebay/nice-modal-react';
// 注意:此处无需再导入 UserInfoModal 组件

function SomeComponent() {
  const handleViewUser = (id) => {
    // 通过注册的ID调用弹窗,并传递参数
    NiceModal.show('user_info_modal', { userId: id });
  };

  return (
    <button onClick={() => handleViewUser(123)}>
      查看用户123
    </button>
  );
}

三、处理异步结果

使用Promise API处理异步结果:NiceModal.show() 返回一个Promise,让你能轻松处理弹窗内的表单提交等异步操作,在弹窗组件内部,你需要调用 modal.resolve(data)modal.reject() 来触发Promise的相应状态

js 复制代码
// 在调用处
NiceModal.show(AddUserModal)
  .then((newUserData) => {
    // 用户在弹窗内点击"确定"并提交了表单
    console.log('新用户数据:', newUserData);
    fetchUsers(); // 刷新列表
  })
  .catch(() => {
    // 用户点击了"取消"
    console.log('操作取消');
  });

核心示例代码:

js 复制代码
// 表单提交处理
const handleSubmit = async () => {
  try {
    setSubmitting(true);
    // 1. 表单验证
    const values = await form.validateFields();
    console.log('表单数据:', values);

    // 2. 模拟一个异步提交请求(例如调用API)
    await new Promise((resolve) => setTimeout(resolve, 1000));
    const mockApiResponse = { id: 123, ...values };

    // 3. ✅ 关键:提交成功,调用 resolve 返回数据给调用方
    modal.resolve(mockApiResponse); // 触发外部 Promise 的 .then

    // 4. 关闭弹窗(建议在 resolve 后调用 hide)
    modal.hide();
    message.success('提交成功!');
  } catch (error) {
    // 处理失败:表单验证错误或API错误
    console.error('提交出错:', error);
    if (!error.errorFields) {
      // 如果不是表单验证错误
      message.error('提交失败,请重试');
      // 可以调用 modal.reject(error) 将错误传递给外部,这里选择不reject,仅提示
    }
  } finally {
    setSubmitting(false);
  }
};

四、注意事项

  1. 状态管理集成(如Redux):

    该库的设计允许将其状态(通过 NiceModal.reducer)集成到Redux store中,方便在Redux DevTools中调试。此时需要注意,Redux的 Provider 必须包裹在 NiceModal.Provider 的外层,弹窗内才能访问到store。

  2. 理解hide与remove的区别:
    modal.hide() 只是隐藏弹窗,组件实例和状态会被保留;modal.remove() 会将组件从DOM树中彻底移除,通常在弹窗关闭动画结束后(如Ant Design的afterClose里)调用以提升性能。

相关推荐
黛色正浓39 分钟前
【React】极客园案例实践-Layout模块
前端·react.js·前端框架
辛-夷41 分钟前
vue高频面试题
前端·vue.js
IT小哥哥呀44 分钟前
《纯前端实现 Excel 导入导出:基于 SheetJS 的完整实战》
前端·excel
文心快码BaiduComate1 小时前
CCF程序员大会码力全开:AI加速营决赛入围名单揭晓,12月6日大理见!
前端·百度·程序员
vivo互联网技术1 小时前
从不足到精进:H5即开并行加载方案的演进之路
前端·h5·webview·客户端·大前端
AwakeFantasy1 小时前
关于fluid打字机问题的解决记录
javascript·博客·hexo·fluid
坐吃山猪1 小时前
Electron03-桌面文件夹
开发语言·javascript·ecmascript
我命由我123451 小时前
微信小程序 - 内容弹出框实现(Vant Weapp 实现、原生实现)
开发语言·前端·javascript·微信小程序·小程序·前端框架·js
裴嘉靖1 小时前
uniapp做的APP和安卓苹果做的什么区别
前端