Creates a portal, allowing rendering of children outside the parent component.
- Use the
useState()
hook to create a state variable that holds therender()
andremove()
functions for the portal. - Use
ReactDOM.createPortal()
andReactDOM.unmountComponentAtNode()
to create a portal and a function to remove it. Use theuseCallback()
hook to wrap and memoize these functions ascreatePortal()
. - Use the
useEffect()
hook to callcreatePortal()
and update the state variable any timeel
‘s value changes. - Finally, return the
render()
function of the state variable.
代码实现
const usePortal = el => {
const [portal, setPortal] = React.useState({
render: () => null,
remove: () => null,
});
const createPortal = React.useCallback(el => {
const Portal = ({ children }) => ReactDOM.createPortal(children, el);
const remove = () => ReactDOM.unmountComponentAtNode(el);
return { render: Portal, remove };
}, []);
React.useEffect(() => {
if (el) portal.remove();
const newPortal = createPortal(el);
setPortal(newPortal);
return () => newPortal.remove(el);
}, [el]);
return portal.render;
};
使用样例
const App = () => {
const Portal = usePortal(document.querySelector('title'));
return (
<p>
Hello world!
<Portal>Portalized Title</Portal>
</p>
);
};
ReactDOM.createRoot(document.getElementById('root')).render(
<App />
);