Popular component renders the Modal, but it will be visible depending on the modal.isVisible Boolean state. My goal is to attach a mouseevent listener and a handler, to close the Modal when clicking outside of it. I tried to do it using useRef, and pass the ref to the Modal dialog, in order to capture the event and check if clicked outside using event.target.contains.
The problem is, on first render I do not want to assign 'mousedown' handler to the document, but only when wrapper && wrapper.current is defined and it outside the Modal dialog. on first render, I can see that the effect runs as expected, but when expanding the Modal by setting isVisible -> true, the ref.current should have changed, but the effect doesn't run again, it will run again if I close the Modal, and then it will work as expecetd. The ref.current changes it not reflected in the effect, even though the effect is supposed to run after the DOM update. Why is that?
const Modal = ({ isVisible, repo, onClose }) => {
const wrapper = useRef();
console.count('render modal');
const escapeHandler = useCallback(({ key }) => {
if (key == 'Escape') onClose();
}, [onClose]);
useEffect(() => {
document.addEventListener('keydown', escapeHandler);
return () => document.removeEventListener('keydown', escapeHandler);
}, []);
useEffect(() => {
// runs after first render, but when setting isVisible to true and causing a rerender
// the effect doesn't run again despite ref.current is changed to <div>
// only after closing the Modal with Escape, it will work as expected, why?
console.count('effect modal');
console.log(wrapper.current);
}, [wrapper.current]);
return !isVisible ? null : (
<div className="modal">
<div className="modal-dialog" ref={wrapper}>
<span className="modal-close" onClick={onClose}>×</span>
{repo && <pre>{JSON.stringify(repo, null, 4)}</pre>}
</div>
</div>
);
};
const Popular = () => {
const [modal, setModal] = useState({ isVisible: false, repo: null });
const closeModal = useCallback(() => {
setModal({ isVisible: false, repo: null });
}, []);
return <Modal onClose={closeModal} {...modal} />
};
However, after reading the docs, if I use a useCallback and pass it as a ref, it works as expetced, like so, why?
const wrapper = useCallback(node => {
// works as expected every time the ref changes
console.log(node);
}, []);
Let me know if the question phrasing is a bit unclear, I'll try to explain a little better