clickOutside 钩子在第二次点击时不起作用

clickOutside hook doesn't work on 2nd click

我有一个项目列表,想要包含一个图标,该图标可以打开模式供用户选择 'edit' 或 'delete' 项目。

我将这段代码放在 ActionModal 中,这样只有通过比较 id 才能打开单击的模式。 问题是,在元素外部单击只能工作一次,之后单击省略号按钮时什么也没有发生。我想可能是因为ActionModal里面的state,'modalOpen'还是false,卡在这里不知道怎么处理。

if (!isOpen.show || isOpen.id !== id || !modalOpen) return null;

const List = () => {
  const [modal, setModal] = useState({ id: null, show: false });

  const onDialogClick = (e) => {
    setModal((prevState) => {
      return { id: e.target.id, show: !prevState.show };
    });
  };

  const journals = journals.map((journal) => (
    <StyledList key={journal.id}>
      <Option>
        <FontAwesomeIcon
          icon={faEllipsisV}
          id={journal.id}
          onClick={onDialogClick}
        />
        <ActionModal
          actions={['edit', 'delete']}
          id={journal.id}
          isOpen={modal}
        ></ActionModal>
      </Option>
const ActionModal = ({ id, actions, isOpen }) => {
  const content = actions.map((action) => <li key={action}>{action}</li>);

  const ref = useRef();
  const [modalOpen, setModalOpen] = useState(true);

  useOnClickOutside(ref, () => setModalOpen(!modalOpen));

  if (!isOpen.show || isOpen.id !== id || !modalOpen) return null;
  return (
    <StyledDiv>
      <ul ref={ref}>{content}</ul>
    </StyledDiv>
  );
};

function useOnClickOutside(ref, handler) {
  useEffect(() => {
    const listener = (event) => {
      if (!ref.current || ref.current.contains(event.target)) {
        return;
      }
      handler(event);
    };
    document.addEventListener('mousedown', listener);
    document.addEventListener('touchstart', listener);
    return () => {
      document.removeEventListener('mousedown', listener);
      document.removeEventListener('touchstart', listener);
    };
  }, [ref, handler]);
}

所以首先你不需要在 useEffect hook 中包含 ref 和 handler 作为依赖项,因为 evvent 侦听器是在初始加载时设置的,不需要在每次值更改时都设置它。

我想我不完全了解你的情况。所以你需要在它打开后通过按下它来关闭模态吗?或者您希望在打开时能够按下那个三点图标?

P.S.

我有点看不起你的代码。试试这个,让我知道发生了什么。 :)

const ActionModal = ({ id, actions, isOpen, setOpen }) => {
  const ref = useRef();

  const content = actions.map((action) => <li key={action}>{action}</li>);

  useEffect(() => {
    const listener = (event) => {
      if (ref.current || !ref.current.contains(event.target)) {
        setOpen({...open, show: false});
      }
    };

    document.addEventListener('mousedown', listener);
    document.addEventListener('touchstart', listener);

    return () => {
      document.removeEventListener('mousedown', listener);
      document.removeEventListener('touchstart', listener);
    };
  }, []);

  return (
    <StyledDiv>
      <div ref={ref}>
        <ul>{content}</ul>
      </div>
    </StyledDiv>
  );
};