I have a list of items and want to include an icon that opens a modal for a user to choose 'edit' or 'delete' the item.
And I put this code inside the ActionModal so that only clicked modal would open by comparing the ids. The problem is, clicking outside the element work only one time and after that, nothing happens when the ellipsis button clicked. I think it's probably because the state inside ActionModal, 'modalOpen' remains false, but I'm stuck here and don't know how to handle it.
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]);
}
