😽
useMergeRef hookとは
UIライブラリのコードを読んでいるとuseMergeRef
hookというのがよく定義されている。
最初はこれが何なのか分からなかったが、refを複数指定するための仕組みだった。
すなわちReact.forwardRefで外側からrefを受け取りつつも、コンポーネント内部でもrefによる操作をしたい。そんな要件を満たすためのものだった。
const Example = React.forwardRef((props, ref) => {
const internalRef = React.useRef()
const refs = useMergeRefs(internalRef, ref)
return (
<div {...props} ref={refs}>
A div with multiple refs.
</div>
)
})
実装は至ってシンプル。
import * as React from "react"
type ReactRef<T> = React.Ref<T> | React.MutableRefObject<T>
export function assignRef<T = any>(ref: ReactRef<T> | undefined, value: T) {
if (ref == null) return
if (typeof ref === "function") {
ref(value)
return
}
try {
ref.current = value
} catch (error) {
throw new Error(`Cannot assign value '${value}' to ref '${ref}'`)
}
}
export function useMergeRefs<T>(...refs: (ReactRef<T> | undefined)[]) {
return React.useMemo(() => {
if (refs.every((ref) => ref == null)) {
return null
}
return (node: T) => {
refs.forEach((ref) => {
if (ref) assignRef(ref, node)
})
}
}, refs)
}
refにはuseRef()で生成したrefオブジェクトとコールバックがあるので、そのへんを考慮している。
複数のrefをまとめた一つのrefを作ると直感的に解釈できなかったのは不甲斐ない。
Discussion