1- import React , { PureComponent } from 'react'
1+ import {
2+ useRef ,
3+ useEffect ,
4+ useMemo ,
5+ memo ,
6+ FC ,
7+ } from 'react'
8+
29import ReactDOM from 'react-dom'
310import htmlTags from 'html-tags'
411
@@ -12,16 +19,19 @@ interface Props {
1219 modalRoot : Element ,
1320}
1421
15- class Modal extends PureComponent < Props > {
16- el : HTMLElement
22+ const Portal : FC < Props > = ( {
23+ tagName,
24+ modalRoot,
25+ children,
26+ } ) => {
27+ const el = useMemo ( ( ) => {
28+ const ns = htmlTags . includes ( tagName ) && tagName !== 'svg' ? HTML_NAMESPACE : SVG_NAMESPACE
29+ return document . createElementNS ( ns , tagName ) as HTMLElement
30+ } , [ tagName , modalRoot ] )
1731
18- constructor ( props ) {
19- super ( props )
20- const ns = htmlTags . includes ( props . tagName ) && props . tagName !== 'svg' ? HTML_NAMESPACE : SVG_NAMESPACE
21- this . el = document . createElementNS ( ns , props . tagName ) as HTMLElement
22- }
32+ const elRef = useRef < Element > ( el )
2333
24- componentDidMount ( ) {
34+ useEffect ( ( ) => {
2535 // The portal element is inserted in the DOM tree after
2636 // the Modal's children are mounted, meaning that children
2737 // will be mounted on a detached DOM node. If a child
@@ -30,19 +40,16 @@ class Modal extends PureComponent<Props> {
3040 // DOM node, or uses 'autoFocus' in a descendant, add
3141 // state to Modal and only render the children when Modal
3242 // is inserted in the DOM tree.
33- this . props . modalRoot . appendChild ( this . el )
34- }
35-
36- componentWillUnmount ( ) {
37- this . props . modalRoot . removeChild ( this . el )
38- }
39-
40- render ( ) {
41- return ReactDOM . createPortal (
42- this . props . children ,
43- this . el , // this.props.modalRoot is possible
44- )
45- }
43+ modalRoot . appendChild ( el )
44+ return ( ) => {
45+ modalRoot . removeChild ( el )
46+ }
47+ } , [ ] )
48+
49+ return ReactDOM . createPortal (
50+ children ,
51+ elRef . current ! , // this.props.modalRoot is possible
52+ )
4653}
4754
48- export default Modal
55+ export default memo ( Portal ) as typeof Portal
0 commit comments