useChildRef
useChildRef
is a React hook for getting or creating a child ref.
Usage
-
If
props.children
has a ref, childRef will be that ref. -
If
props.children
does not have a ref, childRef will be the newly created ref. -
If
props.children
cannot have a ref, childRef will beundefined
. For example, any of your custom components without a forwardRef cannot have a ref.
import useChildRef from 'use-child-ref'
export default function IAmUsingChildRef(props: { children: JSX.Element }) {
const [child, childRef] = useChildRef(props.children)
return child
}
Rules
- You must return
child
from the hook, notprops.children
, for the new ref to work.const [child, childRef] = useChildRef(props.children) return child
-
props.children
must be one element.// Good export function ParentComponent() { return ( <IAmUsingChildRef> <div></div> </IAmUsingChildRef> ) } // Bad export function ParentComponent() { return ( <IAmUsingChildRef> <div></div> <div></div> </IAmUsingChildRef> ) }
- Use forwardRef with your custom component if you want to give access to an element in the component via ref.
import { forwardRef } from 'react' export const WithoutRefAccess = () => { return <h1></h1> } export const WithRefAccess = forwardRef((props, ref) => { return <h1 ref={ref}></h1> }) export const IAmUsingChildRef = (props: { children: JSX.Element }) => { const [child, childRef] = useChildRef(props.children) console.log('childRef: ', typeof childRef) return child } export const ParentComponent = () => { return ( <> <IAmUsingChildRef> {/* childRef: undefined */} <WithoutRefAccess></WithoutRefAccess> </IAmUsingChildRef> <IAmUsingChildRef> {/* childRef: object */} <WithRefAccess></WithRefAccess> </IAmUsingChildRef> </> ) }
Example: Hide Component
Sometimes it's so necessary for legacy third-party code :)
import useChildRef from 'use-child-ref'
export default function Hide(props: { children: JSX.Element; hide: boolean }) {
const [child, childRef] = useChildRef<HTMLElement>(props.children)
useLayoutEffect(() => {
if (childRef?.current) {
childRef.current.style.display = props.hide ? 'none' : ''
}
}, [props.hide])
return child
}