Search code examples
javascriptreactjsreact-hooksuse-ref

Why and how RefObject pass into custom hook automatically?


I'm using several hooks, which applies + - the same logic of the hook usage. But hook on the target element didn't pass the ref of this element through props(parameters) of this hook.

Simplified hook code:

const useHook = () => {
    const containerRef = useRef<HTMLDivElement>(null);

    useEffect(() => {
        if (!containerRef.current) throw new Error('container is not defined'); 
        console.log(containerRef.current) // => and here we will have a reference to the element. Why?
        
        /*some logic*/
    }, []);

    return containerRef;
}

Usage of this hook:

export const TestComponent = () => {
    const hookRef = useHook();

    return <div ref={hookRef}>/*smth else*/</div>
}

Why we create ref, like const hookRef = useHook()?

I'm used to use eventListeners in js like that:

function handler(event) {}
element.addEventListener("click", handler)

In the abovementioned code with event listener we pass event into callback automatically, right? We also can write following code and the results will be the same(on a cursory examination):

function handler(event) {}
element.addEventListener("click", (event) => handler(event))

Right.
But if we were able to do this, then we can do that:

export const TestComponent = () => {
    const hookRef = useHook();

    return <div ref={el => hookRef(el)}>/*smth else*/</div>
}

But no.. We can't. (Yes, I understand, that in the hook function we have no parameters, but, again, how this ref pass into the hook?).

What I need to know to understand this hook/useRef logic? Will be glad to every your answear, thanks a lot.

EDIT
But what if I need to use 2 hooks using refs on the 1 element? Like following:

export const TestComponent = () => {
    const hookRef1 = useHook1();
    const hookRef2 = useHook2();

    return <div ref={el => {
        hookRef1(el) // error
        hookRef2(el) // error
    }}>/*smth else*/</div>

}

How to use the above code correctly?


Solution

  • Following hook returns the RefObject:

    const useHook = () => {
        const containerRef = useRef<HTMLDivElement>(null);
    
        useEffect(() => {
            /*some logic*/
        }, []);
    
        return containerRef; // here it is
    }
    

    so we can just pass variable contains useHook() into ref prop like following:

    const TestComponent = () => {
        const hookRef = useHook();
    
        return <div ref={hookRef}>/*smth else*/</div>
    }
    

    or we can go this way:

    const TestComponent = () => {
        const hookRef = useHook();
        const hookRef2 = useHook2();
    
        return <div ref={element => { // multiple refs
            hookRef.current = element;
            hookRef2.current = element;
        }}>
            example text
        </div>
    
    }