消失的DOM元素未注册点击事件

时间:2019-03-21 10:32:11

标签: reactjs mouseevent mouselistener

我正在React中构造一个看起来像这样的输入字段:

Search box

当单击“ x”(StyledCloseCircle)时,文本将被清除,并且“ x”符号应消失。输入字段为焦点时,当前会在JavaScript中显示“ x”符号

export const Search = React.forwardRef((props, ref) => {
  const [isFocused, setFocus] = useState(false);
  const [isHovered, setHover] = useState(false);

  return (
    <InputContainer
      onMouseEnter={() => setHover(true)}
      onMouseLeave={() => setHover(false)}
    >
      <StyledInput
        onFocus={() => setFocus(true)}
        onBlur={() => setFocus(false)}
        isHovered={isHovered}
        ref={ref}
        {...props}
      />
      {isFocused && !props.value && (
        <StyledMagnifyingGlass
          isHovered={isHovered}
          isFocused={isFocused}
          onClick={props.onSearch}
        />
      )}
      {isFocused && props.value && (
        <StyledCloseCircle onClick={() => console.log("THIS DOES NOT FIRE")} />
      )}
      {!isFocused && (
        <StyledMagnifyingGlass
          isHovered={isHovered}
          isFocused={isFocused}
          onClick={props.onSearch}
        />
      )}
    </InputContainer>
  );
});

问题是,单击“ x”时,输入失去焦点,这将导致在下一个渲染中删除“ x”,并且不注册click事件。但是,它确实会触发mousedown事件。

因此,我的两个问题是:

  1. 单击“ x”会导致注册mousedown而不注册click的操作顺序是什么?
  2. 如何实现所需的行为?

1 个答案:

答案 0 :(得分:1)

您应该创建一个单独的状态来控制显示/隐藏“清除”按钮的位置。像现在一样显示onFocus,但如果用户在输入容器之外单击或单击“清除”按钮,则将其隐藏。您还可以onBlur隐藏它,但是如果用户使用键盘而不是鼠标,则可能会超时(500-1000ms)。

这是以下代码的CodeSnadbox example

function App() {
  const inputContainerRef = useRef();
  const [value, setValue] = useState("");
  const [showClear, setShowClear] = useState(false);

  const onFocus = useCallback(() => {
    setShowClear(true);
  }, []);

  const onClear = useCallback(() => {
    setValue("");
    setShowClear(false);
  }, []);

  const onOutsideClick = useCallback(e => {
    // hide Clear button only if clicked outside of the container
    if (!inputContainerRef.current.contains(e.target)) {
      setShowClear(false);
    }
  }, []);

  useLayoutEffect(
    () => {
      // set the listener only if we shown the Clear button and remove the listener once we hid it
      if (showClear) {
        document.addEventListener("click", onOutsideClick);
        return () => document.removeEventListener("click", onOutsideClick);
      }
    },
    [showClear] // re-invoke if the state changes
  );

  return (
    <div className="App">
      <div className="input-container" ref={inputContainerRef}>
        <input
          value={value}
          onChange={e => {
            setValue(e.target.value);
          }}
          className="input"
          type="tetxt"
          onFocus={onFocus}
        />
        {showClear && (
          <div className="clear" onClick={onClear}>
            X
          </div>
        )}
      </div>
    </div>
  );
}