Last active
September 5, 2022 20:43
-
-
Save enriquebeta6/175612ad7d70906dc15c6bb393e0f738 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Depedencies | |
import React from 'react' | |
import { createPortal } from 'react-dom' | |
// Components | |
import ErrorBoundary from './ErrorBoundary' | |
interface SafePortalProps { | |
rootSelector: string | |
applyCleanup?: boolean | |
} | |
interface SafePortalState { | |
container: Element | null | |
} | |
export default class SafePortal extends React.Component< | |
SafePortalProps, | |
SafePortalState | |
> { | |
constructor(props: SafePortalProps) { | |
super(props) | |
this.state = { | |
container: null, | |
} | |
} | |
componentDidMount() { | |
const { rootSelector, applyCleanup } = this.props | |
const newContainer = document.querySelector(rootSelector) | |
if (newContainer && applyCleanup) { | |
newContainer.innerHTML = '' | |
} | |
this.setState({ | |
container: newContainer, | |
}) | |
} | |
render() { | |
const { children } = this.props | |
const { container } = this.state | |
if (!container) return null | |
return <ErrorBoundary>{createPortal(children, container)}</ErrorBoundary> | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Dependencies | |
import React from 'react' | |
interface ErrorBoundaryProps { | |
fallback?: React.ReactNode | |
children: React.ReactNode | |
} | |
interface ErrorBoundaryState { | |
error: boolean | |
} | |
export default class ErrorBoundary extends React.Component< | |
ErrorBoundaryProps, | |
ErrorBoundaryState | |
> { | |
constructor(props: ErrorBoundaryProps) { | |
super(props) | |
this.state = { | |
error: false, | |
} | |
} | |
componentDidCatch(error: unknown, errorInfo: unknown) { | |
// This console can be changed to an external tool like Sentry | |
console.error({ | |
error, | |
errorInfo, | |
}) | |
this.setState({ | |
error: true, | |
}) | |
} | |
render() { | |
const { error } = this.state | |
const { children, fallback = null } = this.props | |
return error ? fallback : children | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Depedencies | |
import React, { useEffect, useState } from 'react'; | |
import { createPortal } from 'react-dom'; | |
// Components | |
import ErrorBoundary from './ErrorBoundary'; | |
interface SafePortalProps { | |
rootSelector: string; | |
applyCleanup?: boolean; | |
} | |
const SafePortal: React.FC<SafePortalProps> = ({ | |
children, | |
rootSelector, | |
applyCleanup = true, | |
}) => { | |
const [container, setContainer] = useState<HTMLElement>(); | |
useEffect(() => { | |
const element = document.querySelector(rootSelector); | |
if (!element) return; | |
if (applyCleanup) { | |
element.innerHTML = ''; | |
} | |
setContainer(element as HTMLElement); | |
// eslint-disable-next-line react-hooks/exhaustive-deps | |
}, []); | |
if (!container) return null; | |
return <ErrorBoundary>{createPortal(children, container)}</ErrorBoundary>; | |
}; | |
export default SafePortal; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment