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>
);
};
我有一个项目列表,想要包含一个图标,该图标可以打开模式供用户选择 '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>
);
};