Search code examples
javascriptreactjsrefuse-ref

How to pass a ref down more than one level in React?


I can pass a <Parent /> ref to the <Children /> through the forwardRef:

const Children = forwardRef((
  props, ref) => {

  return <div ref={ref}>{props.children}</div>
})

export default function App() {
  const ref = useRef()

  console.log('ref', ref)
  return (
    <Children ref={ref}>I'm a child</Children>
  );
}

But when I add one more level to <GrandChildren /> the ref returns always undefined.

const GrandChildren = forwardRef((props, ref) => {

  return <div ref={ref}>{props.children}</div>
})

const Children = forwardRef((
  props, ref) => {

  return <div><GrandChildren ref={ref} /></div>
})

export default function App() {
  const ref = useRef()

  console.log('ref', ref)
  return (
    <Children ref={ref}>I'm a child</Children>
  );
}


I'm aware we can do this with Context and avoid the prop drilling but for this specific example I'd rather go for prop drilling. any hints?


Solution

  • One option you have is to pass the ref as a prop name rather than ref. For example:

    import { useRef, forwardRef } from "react"
    
    const GrandChildren = forwardRef((props, ref) => {
        return <div ref={ref}>{props.children}</div>
    })
    
    const Children = (props) => {
        return (
            <div>
                {props.children}
                <GrandChildren ref={props.grandchildenRef}>
                    I'm a grandchild
                </GrandChildren>
            </div>
        )
    }
    
    export default function App() {
        const ref = useRef()
        const handleClick = () => {
            console.log("ref", ref)
        }
    
        return (
            <div onClick={handleClick}>
                <Children grandchildenRef={ref}>I'm a child</Children>
            </div>
        )
    }