Skip to content

Commit

Permalink
fix: cleanup timeouts on component unmount
Browse files Browse the repository at this point in the history
refs: CDS-68 (#113)
  • Loading branch information
beawar authored Aug 24, 2022
1 parent 380983e commit c11934b
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 27 deletions.
55 changes: 34 additions & 21 deletions src/components/display/Dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import {
StrictModifiers,
VirtualElement
} from '@popperjs/core';
import { find } from 'lodash';
import { find, forEach } from 'lodash';
import styled, { css, SimpleInterpolation } from 'styled-components';
import { pseudoClasses } from '../../theme/theme-utils';
import { Padding } from '../layout/Padding';
Expand Down Expand Up @@ -402,6 +402,15 @@ const Dropdown = React.forwardRef<HTMLDivElement, DropdownProps>(function Dropdo
const endSentinelRef = useRef<HTMLDivElement | null>(null);
const [position, setPosition] = useState<VirtualElement | null>(null);
const [currentHover, setCurrentHover] = useState<string | null>(null);
const openPopperTimoutRef = useRef<ReturnType<typeof setTimeout>>();

useEffect(
// clear timers on unmount
() => (): void => {
openPopperTimoutRef.current && clearTimeout(openPopperTimoutRef.current);
},
[]
);

useEffect(() => {
setOpen(forceOpen);
Expand Down Expand Up @@ -461,7 +470,7 @@ const Dropdown = React.forwardRef<HTMLDivElement, DropdownProps>(function Dropdo
})
};
setPosition(virtualElement);
setTimeout(() => {
openPopperTimoutRef.current = setTimeout(() => {
if (!disabled && !openRef.current) {
openPopper();
}
Expand Down Expand Up @@ -555,36 +564,40 @@ const Dropdown = React.forwardRef<HTMLDivElement, DropdownProps>(function Dropdo
}, [open, placement, contextMenu, position, dropdownRef, innerTriggerRef]);

useEffect(() => {
if (!disableAutoFocus) {
open &&
setTimeout(() => {
const selectedItems = dropdownRef.current
? dropdownRef.current.querySelectorAll<HTMLElement>('.zapp-selected')
: [];
selectedItems.length > 0
? selectedItems[0].focus()
: popperItemsRef.current &&
popperItemsRef.current.children[0] &&
popperItemsRef.current.children[0] instanceof HTMLElement &&
popperItemsRef.current.children[0].focus();
}, 1);
let timeout: ReturnType<typeof setTimeout>;
if (!disableAutoFocus && open) {
timeout = setTimeout(() => {
const selectedItems = dropdownRef.current
? dropdownRef.current.querySelectorAll<HTMLElement>('.zapp-selected')
: [];
selectedItems.length > 0
? selectedItems[0].focus()
: popperItemsRef.current &&
popperItemsRef.current.children[0] &&
popperItemsRef.current.children[0] instanceof HTMLElement &&
popperItemsRef.current.children[0].focus();
}, 1);
}

return (): void => {
timeout && clearTimeout(timeout);
};
}, [disableAutoFocus, dropdownRef, open]);

useEffect(() => {
openRef.current = open;
let timeout: ReturnType<typeof setTimeout>;
if (open) {
setTimeout(() => windowObj.document.addEventListener('click', clickOutsidePopper, true), 1);
contextMenu &&
setTimeout(
() => windowObj.document.addEventListener('contextmenu', clickOutsidePopper, true),
1
);
timeout = setTimeout(() => {
windowObj.document.addEventListener('click', clickOutsidePopper, true);
contextMenu && windowObj.document.addEventListener('contextmenu', clickOutsidePopper, true);
}, 1);
}

return (): void => {
windowObj.document.removeEventListener('click', clickOutsidePopper, true);
windowObj.document.removeEventListener('contextmenu', clickOutsidePopper, true);
timeout && clearTimeout(timeout);
};
}, [open, closePopper, clickOutsidePopper, contextMenu, windowObj.document]);

Expand Down
3 changes: 2 additions & 1 deletion src/components/display/Tooltip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ const Tooltip = React.forwardRef<HTMLDivElement, TooltipProps>(function TooltipF

useEffect(() => {
// Added timeout to fix Preact weird bug
setTimeout(() => {
const timeout = setTimeout(() => {
if (triggerRef.current && !disabled) {
triggerRef.current.addEventListener('focus', showTooltip);
triggerRef.current.addEventListener('blur', hideTooltip);
Expand All @@ -163,6 +163,7 @@ const Tooltip = React.forwardRef<HTMLDivElement, TooltipProps>(function TooltipF
refSave.removeEventListener('mouseenter', showTooltip);
refSave.removeEventListener('mouseleave', hideTooltip);
}
clearTimeout(timeout);
};
}, [triggerRef, showTooltip, hideTooltip, disabled]);

Expand Down
5 changes: 4 additions & 1 deletion src/components/feedback/CustomModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,10 @@ const CustomModal = React.forwardRef<HTMLDivElement, CustomModalProps>(function
}, [open, onStartSentinelFocus, onEndSentinelFocus, windowObj]);

useEffect(() => {
setTimeout(() => setDelayedOpen(open), 1);
const timeout = setTimeout(() => setDelayedOpen(open), 1);
return (): void => {
clearTimeout(timeout);
};
}, [open]);

const modalWrapperClickHandler = useCallback<React.MouseEventHandler>((e) => {
Expand Down
6 changes: 5 additions & 1 deletion src/components/feedback/Modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,11 @@ const Modal = React.forwardRef<HTMLDivElement, ModalProps>(function ModalFn(
}, [open, onStartSentinelFocus, onEndSentinelFocus, windowObj]);

useEffect(() => {
setTimeout(() => setDelayedOpen(open), 1);
const timeout = setTimeout(() => setDelayedOpen(open), 1);

return (): void => {
clearTimeout(timeout);
};
}, [open]);

return (
Expand Down
7 changes: 4 additions & 3 deletions src/components/utilities/Transition.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -191,15 +191,15 @@ const TransitionOn = React.forwardRef<HTMLElement, TransitionOnProps>(function T
};
}

setTimeout(() => {
const applyStyleTimeout = setTimeout(() => {
if (childElement) {
const fromStyles = from || STYLES[type].from;
applyStyle(fromStyles, childElement);
childElement.style.transition = `${transitionTarget} ${duration}ms ${timing} ${transitionDelay}ms`;
}
}, 1);

const timeout = setTimeout(() => {
const resetStyleTimeout = setTimeout(() => {
if (childElement) {
childElement.style.transition = '';
const endStyles = end || STYLES[type].end || {};
Expand All @@ -208,7 +208,8 @@ const TransitionOn = React.forwardRef<HTMLElement, TransitionOnProps>(function T
}, duration);

return (): void => {
clearTimeout(timeout);
clearTimeout(applyStyleTimeout);
clearTimeout(resetStyleTimeout);
};
}, [
apply,
Expand Down

0 comments on commit c11934b

Please sign in to comment.