文章目录
简单来说,这个库让你像调用函数一样打开一个弹窗,并且这个弹窗的逻辑可以独立编写和复用,非常适合管理大型应用中的复杂弹窗交互
一、使用流程
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、使用
- 首先,你必须在应用根组件外用
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')
);
- 之后,你就可以在任意子组件中,像调用函数一样展示这个弹窗
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')),方便在大型项目中统一管理所有弹窗。
- 创建弹窗组件
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;
- 注册弹窗(关键步骤)
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);
- 在入口文件中导入该文件
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>
);
- 在组件中通过 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);
}
};
四、注意事项
-
状态管理集成(如Redux):
该库的设计允许将其状态(通过
NiceModal.reducer)集成到Redux store中,方便在Redux DevTools中调试。此时需要注意,Redux的 Provider 必须包裹在NiceModal.Provider的外层,弹窗内才能访问到store。 -
理解hide与remove的区别:
modal.hide()只是隐藏弹窗,组件实例和状态会被保留;modal.remove()会将组件从DOM树中彻底移除,通常在弹窗关闭动画结束后(如Ant Design的afterClose里)调用以提升性能。