【@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里)调用以提升性能。

相关推荐
崔庆才丨静觅12 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby606113 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了13 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅13 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅14 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅14 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment14 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅14 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊14 小时前
jwt介绍
前端
爱敲代码的小鱼14 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax