EmojiButton: Eliminate usage of createPortal

This commit is contained in:
Scott Nonnenberg 2023-01-18 16:09:18 -08:00 committed by GitHub
parent 86488b97b9
commit b0e2d22750
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 39 additions and 47 deletions

View file

@ -6,7 +6,6 @@ import type { MutableRefObject } from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import { get, noop } from 'lodash'; import { get, noop } from 'lodash';
import { Manager, Popper, Reference } from 'react-popper'; import { Manager, Popper, Reference } from 'react-popper';
import { createPortal } from 'react-dom';
import { Emoji } from './Emoji'; import { Emoji } from './Emoji';
import type { Props as EmojiPickerProps } from './EmojiPicker'; import type { Props as EmojiPickerProps } from './EmojiPicker';
import { EmojiPicker } from './EmojiPicker'; import { EmojiPicker } from './EmojiPicker';
@ -55,17 +54,17 @@ export const EmojiButton = React.memo(function EmojiButtonInner({
variant = EmojiButtonVariant.Normal, variant = EmojiButtonVariant.Normal,
}: Props) { }: Props) {
const [open, setOpen] = React.useState(false); const [open, setOpen] = React.useState(false);
const [popperRoot, setPopperRoot] = React.useState<HTMLElement | null>(null);
const buttonRef = React.useRef<HTMLButtonElement | null>(null); const buttonRef = React.useRef<HTMLButtonElement | null>(null);
const popperRef = React.useRef<HTMLDivElement | null>(null);
const refMerger = useRefMerger(); const refMerger = useRefMerger();
const handleClickButton = React.useCallback(() => { const handleClickButton = React.useCallback(() => {
if (popperRoot) { if (open) {
setOpen(false); setOpen(false);
} else { } else {
setOpen(true); setOpen(true);
} }
}, [popperRoot, setOpen]); }, [open, setOpen]);
const handleClose = React.useCallback(() => { const handleClose = React.useCallback(() => {
setOpen(false); setOpen(false);
@ -87,22 +86,6 @@ export const EmojiButton = React.memo(function EmojiButtonInner({
emojiButtonApi.current = api; emojiButtonApi.current = api;
} }
// Create popper root and handle outside clicks
React.useEffect(() => {
if (open) {
const root = document.createElement('div');
setPopperRoot(root);
document.body.appendChild(root);
return () => {
document.body.removeChild(root);
setPopperRoot(null);
};
}
return noop;
}, [open, setOpen, setPopperRoot, handleClose]);
React.useEffect(() => { React.useEffect(() => {
if (!open) { if (!open) {
return noop; return noop;
@ -113,9 +96,12 @@ export const EmojiButton = React.memo(function EmojiButtonInner({
handleClose(); handleClose();
return true; return true;
}, },
{ containerElements: [popperRoot, buttonRef], name: 'EmojiButton' } {
containerElements: [popperRef, buttonRef],
name: 'EmojiButton',
}
); );
}, [open, handleClose, popperRoot]); }, [open, handleClose]);
// Install keyboard shortcut to open emoji picker // Install keyboard shortcut to open emoji picker
React.useEffect(() => { React.useEffect(() => {
@ -167,31 +153,30 @@ export const EmojiButton = React.memo(function EmojiButtonInner({
</button> </button>
)} )}
</Reference> </Reference>
{open && popperRoot {open ? (
? createPortal( <div ref={popperRef}>
<Popper placement="top-start" strategy="fixed"> <Popper placement="top-start" strategy="fixed">
{({ ref, style }) => ( {({ ref, style }) => (
<EmojiPicker <EmojiPicker
ref={ref} ref={ref}
i18n={i18n} i18n={i18n}
style={style} style={style}
onPickEmoji={ev => { onPickEmoji={ev => {
onPickEmoji(ev); onPickEmoji(ev);
if (closeOnPick) { if (closeOnPick) {
handleClose(); handleClose();
} }
}} }}
doSend={doSend} doSend={doSend}
onClose={handleClose} onClose={handleClose}
skinTone={skinTone} skinTone={skinTone}
onSetSkinTone={onSetSkinTone} onSetSkinTone={onSetSkinTone}
recentEmojis={recentEmojis} recentEmojis={recentEmojis}
/> />
)} )}
</Popper>, </Popper>
popperRoot </div>
) ) : null}
: null}
</Manager> </Manager>
); );
}); });

View file

@ -2443,6 +2443,13 @@
"updated": "2022-06-14T22:04:43.988Z", "updated": "2022-06-14T22:04:43.988Z",
"reasonDetail": "Handling outside click" "reasonDetail": "Handling outside click"
}, },
{
"rule": "React-useRef",
"path": "ts/components/emoji/EmojiButton.tsx",
"line": " const popperRef = React.useRef<HTMLDivElement | null>(null);",
"reasonCategory": "usageTrusted",
"updated": "2023-01-18T22:32:43.901Z"
},
{ {
"rule": "React-useRef", "rule": "React-useRef",
"path": "ts/components/installScreen/InstallScreenChoosingDeviceNameStep.tsx", "path": "ts/components/installScreen/InstallScreenChoosingDeviceNameStep.tsx",