【问题标题】:How to make react hook persists with ref如何使反应挂钩与 ref 保持一致
【发布时间】:2021-01-09 03:31:05
【问题描述】:

我想使用自定义挂钩来切换输入元素。

这是我的自定义钩子:

import { RefObject, useEffect } from "react";

export const useEscape = (
  ref: RefObject<HTMLElement>,
  triggerFn: () => void
) => {
  useEffect(() => {
    const handleClickOutside = (event: MouseEvent) => {
      if (ref.current && !ref.current.contains(event.target as Node)) {
        triggerFn();
      }
    };
    document.addEventListener("click", handleClickOutside);

    return () => window.removeEventListener("click", handleClickOutside);
  });
};

以及使用钩子的示例

import * as React from "react";
import "./styles.css";
import { useEscape } from "./useEscape";

export default function App() {
  const [showInput, setShowInput] = React.useState(false);
  const inputRef = React.useRef(null);
  useEscape(inputRef, () => {
    if (showInput) setShowInput(false);
  });

  return (
    <div>
      {showInput && (
        <input ref={inputRef} placeholder="click outside to toggle" />
      )}

      {!showInput && (
        <span
          style={{ border: "1px solid black" }}
          onClick={() => {
            console.log("toggle to trigger");
            setShowInput(true);
          }}
        >
          click to toggle input
        </span>
      )}
    </div>
  );
}

这是 link 到代码沙盒演示。

这就是问题所在。在我单击span 元素以切换到输入状态后。在输入元素之外单击后,它将永远无法再次切换回输入状态。

我想我知道为什么会这样。 react ref 仍然指向最初创建的 input 元素。但是,当 react 切换到显示 span 状态时,它会卸载 input 元素,并且我的自定义钩子永远不会与 React 同步以获取新的 input 元素。如何自定义我的 useEscape 挂钩,以便 react ref 同步? (顺便说一句,我不想​​将样式用作视觉上“隐藏”输入元素的解决方法)。

【问题讨论】:

    标签: reactjs react-hooks react-state-management react-ref


    【解决方案1】:
    import { RefObject, useEffect } from "react";
    
    export const useEscape = (
      ref: RefObject<HTMLElement>,
      triggerFn: () => void
    ) => {
      useEffect(() => {
        const handleClickOutside = (event: MouseEvent) => {
          if (ref.current && !ref.current.contains(event.target as Node)) {
            triggerFn();
          }
        };
        document.addEventListener("click", handleClickOutside);
    
        return () => document.removeEventListener("click", handleClickOutside);
      }, [ref, triggerFn]);
    };
    

    你的整个逻辑是绝对正确的。有一个小错误,而不是 window.removeEventListener,改成document.removeEventListener。

    您正在删除导致错误的全局窗口对象上的事件侦听器。

    【讨论】:

      猜你喜欢
      • 2021-09-09
      • 1970-01-01
      • 1970-01-01
      • 2020-03-04
      • 1970-01-01
      • 1970-01-01
      • 2019-02-09
      • 1970-01-01
      • 2020-04-04
      相关资源
      最近更新 更多