From bd1999778d0b4676b607372d30dcfe3b4a75ba7a Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Mon, 6 May 2019 22:22:13 -0700 Subject: [PATCH] Fix bug with ref When using a ref in an effect, you need to use a state ref, otherwise the binding happens too early. --- js/components/FocusTarget.tsx | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/js/components/FocusTarget.tsx b/js/components/FocusTarget.tsx index 8e9f0f53..2c92f58f 100644 --- a/js/components/FocusTarget.tsx +++ b/js/components/FocusTarget.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useRef, useEffect } from "react"; +import React, { useCallback, useState, useEffect } from "react"; import { WindowId, AppState, Dispatch } from "../types"; import * as Actions from "../actionCreators"; import * as Selectors from "../selectors"; @@ -28,39 +28,37 @@ function FocusTarget(props: Props) { } }, [windowId, focusedWindowId, setFocus]); - const ref = useRef(null); + const [ref, setRef] = useState(null); useEffect(() => { - const { current } = ref; - if (current == null || onKeyDown == null) { + if (ref == null || onKeyDown == null) { return; } - current.addEventListener("keydown", onKeyDown); - return () => current.removeEventListener("keydown", onKeyDown); - }, [onKeyDown, windowId, focusedWindowId]); + ref.addEventListener("keydown", onKeyDown); + return () => ref.removeEventListener("keydown", onKeyDown); + }, [onKeyDown, windowId, focusedWindowId, ref]); useEffect(() => { - const { current } = ref; - if (current == null || windowId !== focusedWindowId) { + if (ref == null || windowId !== focusedWindowId) { return; } // I give up. I can't figure out how to type this. const out: EventListener = (e: any) => { - if (!(e.currentTarget as Element).contains(e.relatedTarget as Element)) { - current.focus(); + if (e.relatedTarget == null) { + ref.focus(); } }; // https://github.com/facebook/react/issues/6410 // React does not implement focusout. In this case we prefer focusout to // blur because it gets triggered when a child with focus unmounts. - current.addEventListener("focusout", out); - return () => current.removeEventListener("focusout", out); - }, [windowId, focusedWindowId]); + ref.addEventListener("focusout", out); + return () => ref.removeEventListener("focusout", out); + }, [windowId, focusedWindowId, ref]); return (