nice-modal-react 是一个轻量、灵活的 React 模态框(Modal)管理库,它通过 函数式调用 + Hook 管理状态 的方式,帮助开发者摆脱繁琐的状态控制(如 visible, onClose),实现更简洁、解耦的模态框开发体验。
📦 安装
npm install nice-modal-react
或使用 yarn:
yarn add nice-modal-react
🧩 基本结构:必须包裹 Provider
在应用根部使用 <NiceModalProvider> 包裹你的组件树。
// App.jsx
import React from 'react';
import { NiceModalProvider } from 'nice-modal-react';
import MainPage from './MainPage';
function App() {
return (
<NiceModalProvider>
<div className="App">
<MainPage />
</div>
</NiceModalProvider>
);
}
export default App;
⚠️ 所有功能都依赖此 Provider,请确保已正确引入。
✅ 使用方式一:函数式调用(推荐)
最常用的模式,通过 show() 函数动态弹出模态框。
步骤 1:创建并包装 Modal 组件
// components/MyModal.jsx
import React from 'react';
import { useModal } from 'nice-modal-react';
const MyModal = ({ title = '提示', children }) => {
const { visible, hide } = useModal();
if (!visible) return null;
return (
<div className="modal-overlay">
<div className="modal-content">
<h3>{title}</h3>
<p>{children}</p>
<button onClick={hide}>关闭</button>
</div>
</div>
);
};
// 使用 niceModal 包装组件(关键步骤)
export default niceModal(MyModal);
💡 注意:必须使用 niceModal() 高阶函数包装组件才能被识别。
步骤 2:函数式调用
import { show } from 'nice-modal-react';
import MyModal from './components/MyModal';
function App() {
const openModal = () => {
show(MyModal, {
title: '欢迎',
children: '这是一个简单的模态框',
});
};
return <button onClick={openModal}>打开模态框</button>;
}
✅ 优点:
- 无需维护
visible状态 - 支持传参
- 调用简单清晰
✅ 使用方式二:使用 useModal 控制行为
在 Modal 内部使用 useModal() 获取控制能力。
可用属性与方法:
| 属性/方法 | 类型 | 说明 |
|---|---|---|
visible | boolean | 当前是否可见 |
hide() | function | 隐藏当前 modal |
remove() | function | 销毁实例(从 DOM 移除) |
resolve(value) | function | 返回结果(用于异步等待) |
reject(err) | function | 抛出错误(配合 await 使用) |
示例:带返回值的确认框
// components/ConfirmModal.jsx
import React from 'react';
import { useModal } from 'nice-modal-react';
const ConfirmModal = ({ message = '确认操作?' }) => {
const { visible, resolve } = useModal();
if (!visible) return null;
return (
<div className="modal-overlay">
<div className="modal-content">
<p>{message}</p>
<button onClick={() => resolve(true)}>确定</button>
<button onClick={() => resolve(false)}>取消</button>
</div>
</div>
);
};
export default niceModal(ConfirmModal);
异步调用并获取结果:
import { show } from 'nice-modal-react';
import ConfirmModal from './components/ConfirmModal';
const handleDelete = async () => {
const confirmed = await show(ConfirmModal, {
message: '确定要删除这条数据吗?',
});
if (confirmed) {
console.log('执行删除');
}
};
✅ 适用场景:表单提交确认、登录弹窗、选择器等需要“等待用户反馈”的交互。
✅ 使用方式三:模板式渲染(传统风格)
将 Modal 当作普通组件插入 JSX 中,但仍受 nice-modal-react 管理。
import React from 'react';
import { NiceModal } from 'nice-modal-react';
import MyModal from './components/MyModal';
const App = () => {
return (
<div>
{/* 渲染指定 ID 的 modal */}
<NiceModal id={MyModal.id} title="来自模板" />
{/* 或者多个参数 */}
<NiceModal id={MyModal.id} {...{ title: '动态标题' }} />
</div>
);
};
✅ 适用场景:
- SSR(服务端渲染)
- 需要在特定位置渲染 modal
- 与某些 UI 框架深度集成时
⚠️ 注意:仍需先用 niceModal() 包装组件。
✅ 使用方式四:动态内联 Modal(无需定义组件)
直接在事件中创建一个临时的匿名 Modal。
import React from 'react';
import { show } from 'nice-modal-react';
const App = () => {
const openInline = () => {
show(
({ visible, hide }) => {
return visible ? (
<div style={{ ...overlayStyle }}>
<div style={{ ...contentStyle }}>
<h3>内联 Modal</h3>
<p>这是即时创建的弹窗</p>
<button onClick={hide}>关闭</button>
</div>
</div>
) : null;
},
{ id: 'temp-modal' } // 可选唯一标识
);
};
return <button onClick={openInline}>打开内联 Modal</button>;
};
✅ 优点:适合调试、快速原型、一次性弹窗。
🔧 全局控制 API
nice-modal-react 提供了一些全局控制方法,用于管理所有 modal 实例。
| 方法 | 说明 |
|---|---|
show(Component, props) | 显示某个 modal |
hide(id) | 隐藏指定 modal |
remove(id) | 销毁指定 modal |
clear() | 关闭并销毁所有 modal |
visibleModals | 获取当前所有可见 modal 的数组 |
示例:
import { hide, clear, visibleModals } from 'nice-modal-react';
// 关闭某个 modal
hide(MyModal.id);
// 清空所有 modal
clear();
// 查看当前激活的 modals
console.log(visibleModals); // [{ id, component, props }]
🔄 Modal ID 说明
每个被 niceModal() 包装的组件都会自动生成一个唯一的 id(通常是组件名或手动指定)。
你也可以手动指定:
const MyModal = niceModal(() => { ... }, 'my-custom-id');
console.log(MyModal.id); // "my-custom-id"
💡 最佳实践建议
| 场景 | 推荐方式 |
|---|---|
| 普通弹窗(提示、通知) | 函数式调用 + show() |
| 确认对话框、登录框 | await show(...) 异步模式 |
| 复杂交互逻辑 | useModal() 自定义控制 |
| 快速调试 / 临时弹窗 | 内联 Modal |
| SSR 或静态布局 | 模板式 <NiceModal id={...} /> |
🎨 样式建议(CSS 示例)
.modal-overlay {
position: fixed;
top: 0; left: 0;
width: 100vw;
height: 100vh;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
z-index: 1000;
}
.modal-content {
background: white;
padding: 2rem;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
max-width: 400px;
text-align: center;
}
📚 参考资源
- GitHub 仓库: github.com/easy-team/n…
- npm 页面: www.npmjs.com/package/nic…
❓ 常见问题
Q: 为什么 modal 不显示?
A: 检查是否遗漏 <NiceModalProvider>,或未使用 niceModal() 包装组件。
Q: 如何防止重复打开同一个 modal?
A: nice-modal-react 默认允许叠加。若需单例,可在业务层加锁判断,或使用 hide/remove 控制。
Q: 能否和 Ant Design Modal 结合?
A: 可以!后续可提供示例(如封装 Modal.confirm 风格)。
📝 附录:TypeScript 支持示例
// components/TypedModal.tsx
import React from 'react';
import { useModal } from 'nice-modal-react';
interface Props {
title: string;
onOk?: () => void;
}
const TypedModal: React.FC<Props> = ({ title, onOk }) => {
const { visible, hide } = useModal();
return visible ? (
<div className="modal">
<h3>{title}</h3>
<button onClick={() => { onOk?.(); hide(); }}>确定</button>
<button onClick={hide}>取消</button>
</div>
) : null;
};
export default niceModal(TypedModal);
如有需要,还可提供:
- Ant Design 集成示例
- Redux/Saga 中调用 modal
- 多语言支持方案
- 动画过渡效果处理
欢迎继续提问!💡