Skip to content

Instantly share code, notes, and snippets.

@YuCJ
Last active August 30, 2020 15:41
Show Gist options
  • Save YuCJ/bfd8e16eae07f55fe6cc3cee70e13ad3 to your computer and use it in GitHub Desktop.
Save YuCJ/bfd8e16eae07f55fe6cc3cee70e13ad3 to your computer and use it in GitHub Desktop.
In React, we use `ref` to touch the DOM element directly. When a component takes refs passed by its parent, and it needs to touch the DOM element by itself also, we have to compose the refs into one so we can pass it to the child..
function updateElementInRef(element, ref) {
if (typeof ref === 'function') {
/*
The ref is a callback ref.
https://reactjs.org/docs/refs-and-the-dom.html#callback-refs
*/
ref(element)
} else if (ref) {
/*
The ref is an object expected to be mutated with property `current`.
It's the returned object of React.useRef() hook (interface React.MutableRefObject)
or the returned object of React.createRef() (interface React.RefObject).
*/
ref.current = element
} else {
/* Not a valid ref. Handle the exceptions here */
}
}
export default function composeRefs(...refs) {
return function composedRef(element) {
const refCount = refs.length
for (let i = 0; i < refCount; i += 1) {
const ref = refs[i]
updateElementInRef(element, ref)
}
}
}
/* USAGE EXAMPLE */
const ForwardRefVideo = React.forwardRef((props, upperRef) => {
const videoEleRef = React.useRef(null)
const composedRef = composeRefs(videoEleRef, upperRef)
/* `videoEleRef.current` will be the video DOM element */
return (
<video ref={composedRef}>
{props.sources.map((source, i) => (
<source key={`${i}-source`} src={source.src} type={source.type} />
))}
<p>This browser does not support the video element.</p>
</video>
)
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment