From fed47b8fe21c025ca4ebdcf3cd8ad5ef90752cb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rahel=20Lu=CC=88thy?= Date: Wed, 12 Jun 2019 15:11:35 +0200 Subject: [PATCH] #15: Guarantee listener removal even if triggeringRef becomes null --- src/Tooltip.tsx | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/src/Tooltip.tsx b/src/Tooltip.tsx index 1e2caa6..31e4793 100644 --- a/src/Tooltip.tsx +++ b/src/Tooltip.tsx @@ -24,12 +24,17 @@ type State = TooltipHidden | TooltipVisible export class TooltipComponent extends React.Component { public readonly state: Readonly = { type: 'TooltipHidden' } + // Keep a reference to the mouse event triggering DOM node + // `triggerRef` may be null by the time we want to remove listeners + private safeMouseTrigger + public componentDidMount() { const mouseTrigger = this.props.triggerRef.current if (mouseTrigger && mouseTrigger.addEventListener) { - mouseTrigger.addEventListener(`mouseover`, this.updateTooltipListener) - mouseTrigger.addEventListener(`mousemove`, this.updateTooltipListener) - mouseTrigger.addEventListener(`mouseleave`, this.hideTooltipListener) + this.safeMouseTrigger = mouseTrigger + mouseTrigger.addEventListener(`mouseover`, this.updateTooltip) + mouseTrigger.addEventListener(`mousemove`, this.updateTooltip) + mouseTrigger.addEventListener(`mouseleave`, this.hideTooltip) } } @@ -55,21 +60,19 @@ export class TooltipComponent extends React.Component { } public componentWillUnmount() { - const mouseTrigger = this.props.triggerRef.current - if (mouseTrigger && mouseTrigger.removeEventListener) { - mouseTrigger.removeEventListener(`mouseover`, this.updateTooltipListener) - mouseTrigger.removeEventListener(`mousemove`, this.updateTooltipListener) - mouseTrigger.removeEventListener(`mouseleave`, this.hideTooltipListener) + if (this.safeMouseTrigger && this.safeMouseTrigger.removeEventListener) { + this.safeMouseTrigger.removeEventListener(`mouseover`, this.updateTooltip) + this.safeMouseTrigger.removeEventListener(`mousemove`, this.updateTooltip) + this.safeMouseTrigger.removeEventListener(`mouseleave`, this.hideTooltip) } } - private readonly updateTooltipListener = (evt: MouseEvent) => { + private readonly updateTooltip = (evt: MouseEvent) => { if (this.props) { - const mouseTrigger = this.props.triggerRef.current const svg = this.props.containerRef ? this.props.containerRef.current - : mouseTrigger - ? mouseTrigger.ownerSVGElement + : this.safeMouseTrigger + ? this.safeMouseTrigger.ownerSVGElement : undefined if (svg) { const mousePosition = svgPoint(svg, evt) @@ -83,7 +86,7 @@ export class TooltipComponent extends React.Component { } } - private readonly hideTooltipListener = () => { + private readonly hideTooltip = () => { this.setState({ type: 'TooltipHidden' }) } }