首页 > 解决方案 > 参考问题和 useEffect 后调用自定义挂钩

问题描述

我正在使用自定义挂钩来检测外部点击

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

问题是我的自定义钩子useClickOutsidemodalRef.current称为null

正如您在useEffet钩子中看到的那样,该modalRef.current值是正确的

但是我不能在那里调用我的自定义钩子,useEffet否则我会得到Uncaught Invariant Violation: Hooks can only be called inside the body of a function component

那么如何解决这个问题呢?

标签: reactjsreact-hooks

解决方案


如果你只传递 ref,而不是传递 ref.current,你的代码将工作,因为 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>
    )
}

工作演示


推荐阅读