Skip to content

Commit

Permalink
fix: do not create new element with every render #2025
Browse files Browse the repository at this point in the history
  • Loading branch information
marek-mihok committed Aug 28, 2023
1 parent d3d83fd commit 6143f7b
Showing 1 changed file with 6 additions and 10 deletions.
16 changes: 6 additions & 10 deletions ui/src/copyable_text.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ type ClipboardCopyButton = {
value: S,
/** The element to which the copy button is attached. */
anchorElement: HTMLElement | undefined,
/** Show copy button only on hover. */
/** Show copy button only on hover over anchor element. */
showOnHoverOnly?: B,
/** Use portal if ClipboardCopyButton is not direct child of the anchor element. */
portal?: B
Expand All @@ -75,12 +75,11 @@ export const ClipboardCopyButton = ({ value, anchorElement, showOnHoverOnly = fa
timeoutRef = React.useRef<U>(),
[copied, setCopied] = React.useState(false),
[visible, setVisible] = React.useState(!showOnHoverOnly),
btnContainerRef = React.useRef<HTMLDivElement>(document.createElement('div')),
onClick = React.useCallback(async () => {
if (!anchorElement) return
try {
if (document.queryCommandSupported('copy')) {
anchorElement.select()
(anchorElement as any)?.select()
document.execCommand('copy')
window.getSelection()?.removeAllRanges()
}
Expand All @@ -92,28 +91,25 @@ export const ClipboardCopyButton = ({ value, anchorElement, showOnHoverOnly = fa
timeoutRef.current = window.setTimeout(() => setCopied(false), 2000)
}, [anchorElement, value]),
CopyButton = React.useMemo(() => <Fluent.PrimaryButton
id='copybutton'
title='Copy to clipboard'
onClick={onClick}
iconProps={{ iconName: copied ? 'CheckMark' : 'Copy' }}
className={clas(css.btn, copied ? css.copiedBtn : '', showOnHoverOnly ? css.animate : '', visible ? css.visible : '')}
/>, [copied, onClick, showOnHoverOnly, visible])

React.useEffect(() => {
if (!anchorElement) return
if (portal) ReactDOM.render(ReactDOM.createPortal(CopyButton, anchorElement), btnContainerRef.current)
if (showOnHoverOnly) {
if (anchorElement && showOnHoverOnly) {
anchorElement.addEventListener('mouseenter', () => setVisible(true))
anchorElement.addEventListener('mouseleave', (ev: MouseEvent) => {
if ((ev.relatedTarget as HTMLElement)?.id === 'copybutton') return
setVisible(false)
})
}
}, [CopyButton, anchorElement, portal, showOnHoverOnly])
}, [anchorElement, showOnHoverOnly])

React.useEffect(() => () => window.clearTimeout(timeoutRef.current), [])

return portal ? null : CopyButton
return portal && anchorElement ? ReactDOM.createPortal(CopyButton, anchorElement) : CopyButton
}

export const XCopyableText = ({ model }: { model: CopyableText }) => {
Expand All @@ -130,7 +126,7 @@ export const XCopyableText = ({ model }: { model: CopyableText }) => {
<>
<Fluent.TextField
data-test={name}
// Temporary solution which will be replaced with ref once TextField is converted to a function component.
// Temporary solution which will be replaced with 'ref' once Fluent.TextField is converted to a function component.
elementRef={domRef}
value={value}
multiline={multiline}
Expand Down

0 comments on commit 6143f7b

Please sign in to comment.