3

I am using a custom hook to detect outside clicks

const useClickOutside = (nodeElement, handler) => {

    function handleClickOutside(event) {
        if (nodeElement && !nodeElement.contains(event.target)) {
            handler();
        }
    }

    useEffect(() => {
        document.addEventListener('mousedown', handleClickOutside);
        return () =>  document.removeEventListener('mousedown', handleClickOutside);
    }, []);  
} 

And I am calling it like this

const Modal = ({ ... }) => {

    const modalRef = useRef(null);

    console.log(modalRef.current) // null

    useEffect(() => {
        console.log(modalRef.current) // work fine here and display the dom element
    }, [])

    // here the hooks it is called with modalRef.current as null
    useClickOutside(modalRef.current, () => { 
        dispatch(hideModal());
    });

    return (
        <div className="pop-container">
            <div className="pop-dialog" ref={modalRef}>
                ...
            </div>
        </div>
    )
}

The problem is that my custom hooks useClickOutside is called with modalRef.current as null

And as you see in the useEffet hook the modalRef.current value is correct

However i can't call my custom hook there in useEffet otherwise i will get Uncaught Invariant Violation: Hooks can only be called inside the body of a function component

So how to solve this issue ?

1 Answer 1

1

Instead of passing ref.current, if you just pass ref, your code will work since ref.current will be mutated at its reference when ref is assigned

const useClickOutside = (nodeElement, handler) => {

    function handleClickOutside(event) {
        if (nodeElement.current && !nodeElement.current.contains(event.target)) {
            handler();
        }
    }

    useEffect(() => {
        document.addEventListener('mousedown', handleClickOutside);
        return () =>  document.removeEventListener('mousedown', handleClickOutside);
    }, []);  
} 

and in modal

const Modal = ({ ... }) => {

    const modalRef = useRef(null);

    // here the hooks it is called with modalRef.current as null
    useClickOutside(modalRef, () => { 
        dispatch(hideModal());
    });

    return (
        <div className="pop-container">
            <div className="pop-dialog" ref={modalRef}>
                ...
            </div>
        </div>
    )
}

Working demo

Sign up to request clarification or add additional context in comments.

1 Comment

To clarify, in the original version, nodeElement === null when useClickOutside is first called. The fact that modalRef.current === div later on doesn't change the value of nodeElement.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.