this.wrapperRef.current.contains(element) returns false 虽然元素是孙子

this.wrapperRef.current.contains(element) returns false although element is a grand child

包装器 EditModal 组件带有 onClickOutside 事件。此模式的子组件是 Material-UI Select。单击 MenuItem 会触发 onClickOutside,从而在未选择新值的情况下关闭模式。

问题的根源是 this.wrapperRef.current.contains(element) 返回 false,即使 MenuItemEditModal 的孙子。

为什么会这样?如何避免这种行为?

https://codesandbox.io/s/select-inside-edit-modal-l69zj?file=/src/edit-modal.js (代码改编自this blog

import React, { createRef } from "react";
import Select from "@material-ui/core/Select";
import MenuItem from "@material-ui/core/MenuItem";

class EditModal extends React.Component {
  constructor(props) {
    super(props);
    this.wrapperRef = createRef();
    this.state = { value: props.initialValue };
  }

  componentDidMount() {
    document.body.addEventListener("mousedown", this.onClickOutside);
  }

  componentWillUnmount() {
    document.removeEventListener("mousedown", this.onClickOutside);
  }

  onClickOutside = (e) => {
    const { onClose } = this.props;
    const element = e.target;

    if (this.wrapperRef.current && !this.wrapperRef.current.contains(element)) {
      console.log(this.wrapperRef.current.contains(element));
      e.preventDefault();
      e.stopPropagation();
      onClose();
    }
  };

  onChange = (e) => {
    const { onClose } = this.props;

    this.setState({ value: e.target.value });
    this.props.onChange(e.target.value);
    onClose();
  };

  render() {
    const value = this.state.value;

    return (
      <div className="modal--overlay">
        <div className="modal" ref={this.wrapperRef}>
          <h1>Select a new value</h1>
          <Select
            id="demo-customized-select"
            value={value}
            color="primary"
            onChange={this.onChange}
          >
            <MenuItem value={"A"}>A</MenuItem>
            <MenuItem value={"B"}>B</MenuItem>
            <MenuItem value={"C"}>C</MenuItem>
          </Select>
        </div>
      </div>
    );
  }
}

export default EditModal;

一位同事找到了答案。 Material-UI 生成的弹出菜单未作为 DOM 中 Select 的子项放置。

要修复 onClickOutside,应使用 Select 属性 MenuProps.

添加引用此菜单的附加条件

https://codesandbox.io/s/select-inside-edit-modal-forked-wrz7t?file=/src/edit-modal.js:1382-1448

  [...]

    this.wrapperRef = createRef();
    this.inputRef = createRef();

  [...]

    if (
       this.wrapperRef.current &&
       !this.wrapperRef.current.contains(element) &&
       (this.inputRef.current === null ||
       (this.inputRef.current && !this.inputRef.current.contains(element)))
       ) {

  [...]
          <Select
            MenuProps={{
              ref: this.inputRef
            }}
            id="demo-customized-select"
            value={value}
            color="primary"
            onChange={this.onChange}
          >

  [...]