首页 > 解决方案 > React:当焦点子组件卸载时如何捕获焦点

问题描述

我有一个可以获得焦点的父组件。它使用这个焦点来提供键盘控制。该父组件可以生成一个子组件,该子组件同样可以获取焦点,以便它可以响应键盘事件。子组件侦听的键盘事件之一是<esc>导致子组件被卸载。

当子组件卸载时,焦点返回到<body>文档的。

我的父组件如何检测到这种情况何时发生并将焦点重新分配给它自己?

到目前为止我所知道的:

编辑:我正在寻找一种不涉及父组件和子组件之间直接通信/耦合的解决方案。想象一下,在任意深嵌套的树上,可能有我任意多个这样的孩子。

标签: reactjs

解决方案


我最终使用 MutationObserver 解决了这个问题。

代码如下所示:

// It's possible for a child component to gain focus and then become
// unmounted. In that case, the browser will return focus to the `<body>`.
// In the following hook, use a `MutationObserver` to watch for that behavior
// and refocus the containing FocusTarget when it happens.
//
// I tried a number of other approaches using `focus/blur/focusin/focusout` on
// various DOM nodes, and was unable to find a solution which would trigger in
// this senario in Firefox. Therefore we use this `MutationObserver` approach.
useEffect(() => {
  // Only create the `MutationObserver` within the currently focused target.
  if (ref == null || windowId !== focusedWindowId) {
    return;
  }

  const observer = new MutationObserver(mutations => {
    // In the common case we won't have focused the body, so we can do this
    // inexpensive check first to avoid calling the more expensive `O(n)`
    // check of the individual mutations.
    if (document.activeElement !== document.body) {
      return;
    }
    if (mutations.some(mutation => mutation.removedNodes.length > 0)) {
      ref.focus();
    }
  });

  observer.observe(ref, {
    subtree: true,
    attributes: false,
    childList: true
  });

  return () => observer.disconnect();
}, [windowId, focusedWindowId, ref]);

添加它的实际提交:https ://github.com/captbaritone/webamp/commit/2dca07ff0a97ad378a1a050513255d2ba129dbcd


推荐阅读