@siroi/react-portal
v0.1.0-beta.2
Published
A simple and intuitive React portal library for easy DOM mounting
Readme
@siroi/react-portal
一个简单直观的React Portal库,用于简化DOM挂载操作。
特性
- 🎯 极简API:像使用普通组件一样使用Portal
- 🔄 保持上下文:自动透传React Context
- 🎨 多种使用方式:组件、Hook、HOC三种选择
- 📦 轻量级:只解决挂载问题,不做过度设计
- 🛡️ 类型安全:完整的TypeScript支持
- 🌐 SSR友好:服务端渲染安全
安装
npm install @siroi/react-portal
# 或
yarn add @siroi/react-portal
# 或
pnpm add @siroi/react-portal快速开始
1. Portal组件(推荐)
import { Portal } from '@siroi/react-portal';
function App() {
const [isOpen, setIsOpen] = useState(false);
return (
<div>
<button onClick={() => setIsOpen(true)}>
打开Modal
</button>
{isOpen && (
<Portal>
<div className="modal">
<h2>Modal标题</h2>
<p>内容...</p>
<button onClick={() => setIsOpen(false)}>
关闭
</button>
</div>
</Portal>
)}
</div>
);
}2. usePortal Hook
import { usePortal } from '@siroi/react-portal';
function App() {
const [isOpen, setIsOpen] = useState(false);
const { portal } = usePortal();
return (
<div>
<button onClick={() => setIsOpen(true)}>
打开Modal
</button>
{isOpen && portal(
<div className="modal">
<h2>Modal标题</h2>
<p>内容...</p>
<button onClick={() => setIsOpen(false)}>
关闭
</button>
</div>
)}
</div>
);
}3. createPortal HOC
import { createPortal } from '@siroi/react-portal';
function Modal({ children, onClose }) {
return (
<div className="modal">
{children}
<button onClick={onClose}>关闭</button>
</div>
);
}
const PortalModal = createPortal(Modal);
function App() {
const [isOpen, setIsOpen] = useState(false);
return (
<div>
<button onClick={() => setIsOpen(true)}>
打开Modal
</button>
{isOpen && (
<PortalModal onClose={() => setIsOpen(false)}>
<h2>Modal标题</h2>
<p>内容...</p>
</PortalModal>
)}
</div>
);
}API 文档
<Portal /> 组件
| 属性 | 类型 | 默认值 | 描述 |
|------|------|--------|------|
| children | ReactNode | - | Portal内容 |
| to | HTMLElement | document.body | 挂载目标元素 |
| autoCleanup | boolean | true | 是否自动清理 |
| key | string \| null | null | React key |
usePortal(options) Hook
const { portal, cleanup, target } = usePortal({
to: document.body, // 挂载目标
autoCleanup: true, // 自动清理
key: null, // React key
});createPortal(Component, config) HOC
const PortalComponent = createPortal(Component, {
to: document.body, // 挂载目标
autoCleanup: true, // 自动清理
key: null, // React key
displayName: 'PortalComponent', // 组件名称
});高级用法
自定义挂载目标
function App() {
const [container, setContainer] = useState(null);
const containerRef = useCallback((node) => {
if (node) setContainer(node);
}, []);
return (
<div>
<div ref={containerRef} className="custom-container">
自定义容器
</div>
<Portal to={container}>
<div>渲染到自定义容器</div>
</Portal>
</div>
);
}批量创建Portal组件
import { createPortalFactory } from '@siroi/react-portal';
// 创建工厂函数
const createBodyPortal = createPortalFactory({ to: document.body });
// 批量创建Portal组件
const PortalModal = createBodyPortal(Modal);
const PortalTooltip = createBodyPortal(Tooltip);
const PortalDropdown = createBodyPortal(Dropdown);与原生createPortal对比
原生方式
import { createPortal } from 'react-dom';
function Component() {
return createPortal(
<div>内容</div>,
document.body,
'portal-key'
);
}@siroi/react-portal方式
import { Portal } from '@siroi/react-portal';
function Component() {
return (
<Portal to={document.body} key="portal-key">
<div>内容</div>
</Portal>
);
}优势:
- 更符合React组件思维
- 自动处理SSR场景
- 更好的类型提示
- 支持多种使用模式
开发
构建
npm run build开发模式
npm run dev清理构建产物
npm run clean技术细节
构建输出
这个包使用纯TypeScript编译,输出ES模块格式:
dist/index.js- 编译后的JavaScript代码dist/index.d.ts- TypeScript类型定义
依赖关系
- peerDependencies:
react,react-dom - devDependencies:
typescript,@types/react,@types/react-dom,rimraf
设计理念
- 简单优先:API设计直观易用
- 零配置:合理的默认值,开箱即用
- 类型安全:完整的TypeScript支持
- 最小依赖:只依赖React,不引入额外负担
许可证
MIT © siroi
