Ссылка на проблему и вызов пользовательского хука после useEffect - PullRequest
1 голос
/ 27 марта 2019

Я использую пользовательский хук для обнаружения внешних кликов

const useClickOutside = (nodeElement, handler) => {

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

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

И я называю это так

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>
    )
}

Проблема в том, что мой пользовательский хук useClickOutside называетсяс modalRef.current как null

И, как вы видите в useEffet хуке, значение modalRef.current правильное

Однако я не могу вызвать свой пользовательский хук там в useEffet иначе я получу Uncaught Invariant Violation: Hooks can only be called inside the body of a function component

Так как решить эту проблему?

1 Ответ

1 голос
/ 27 марта 2019

Вместо передачи ref.current, если вы просто передадите ref, ваш код будет работать, так как ref.current будет мутирован по своей ссылке, когда ref присваивается

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);
    }, []);  
} 

и в модальном

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>
    )
}

Рабочая демонстрация

...