HextaUI

useMergedRef

Herhangi sayıda callback ve nesne ref'ini, her biri için React 19 ref temizliğiyle tek bir ref'te birleştirir.

0px
"use client"

import * as React from "react"

import { Button } from "@/components/ui/button"
import { useMergedRef } from "@/hooks/use-merged-ref"

function MeasuredBox({
  ref,
  onWidth,
  ...props
}: React.ComponentProps<"div"> & { onWidth: (width: number) => void }) {
  const measureRef = React.useCallback(
    (node: HTMLDivElement | null) => {
      if (!node) {
        return
      }
      const observer = new ResizeObserver(([entry]) =>
        onWidth(Math.round(entry.contentRect.width))
      )
      observer.observe(node)
      return () => observer.disconnect()
    },
    [onWidth]
  )
  const setRef = useMergedRef(ref, measureRef)

  return <div ref={setRef} {...props} />
}

export function UseMergedRefDemo() {
  const ref = React.useRef<HTMLDivElement>(null)
  const [width, setWidth] = React.useState(0)
  const [wide, setWide] = React.useState(false)

  return (
    <div className="flex w-full max-w-sm flex-col items-center gap-4">
      <MeasuredBox
        ref={ref}
        onWidth={setWidth}
        data-wide={wide ? "" : undefined}
        className="flex h-16 w-1/2 items-center justify-center rounded-lg bg-muted font-mono text-sm tabular-nums transition-all duration-300 ease-out-quint data-wide:w-full motion-reduce:transition-none"
      >
        {width}px
      </MeasuredBox>
      <div className="flex gap-2">
        <Button variant="outline" size="sm" onClick={() => setWide((v) => !v)}>
          Resize
        </Button>
        <Button
          variant="ghost"
          size="sm"
          onClick={() =>
            ref.current?.animate(
              [{ scale: 1 }, { scale: 0.96 }, { scale: 1 }],
              { duration: 240, easing: "ease-out" }
            )
          }
        >
          Nudge via parent ref
        </Button>
      </div>
    </div>
  )
}
pnpm dlx shadcn@latest add https://hextaui.com/r/use-merged-ref.json

Hook'u ve bağımlı olduğu her şeyi projenize ekler.

import { useMergedRef } from "@/hooks/use-merged-ref"
function Panel({ ref, ...props }: React.ComponentProps<"div">) {
  const localRef = React.useRef<HTMLDivElement>(null)
  const morphRef = useSizeMorph<HTMLDivElement>({ axis: "height" })
  const setRef = useMergedRef(ref, localRef, morphRef)

  return <div ref={setRef} {...props} />
}

Bir öğenin tek bir ref'i vardır, ama bileşenler çoğu zaman onu birkaç yere vermek ister: ref ileten üst öğe, effect'ler için yerel bir ref ve geri çağırma ref'iyle çalışan hook'lar. useMergedRef hepsini besleyen tek bir geri çağırma döndürür.

Öğe bağlandığında her ref onu alır. Nesne ref'lerinde .current ayarlanır, geri çağırma ref'leri düğümle çağrılır. Birleştirilmiş geri çağırma React 19 tarzında bir temizleme döndürür. Ayrılırken her geri çağırma ref'inin kendi temizlemesini çalıştırır veya bir tane döndürmediyse ref'i null ile çağırır ve nesne ref'lerini null'a sıfırlar.

const observeRef = React.useCallback((node: HTMLDivElement | null) => {
  if (!node) return
  const observer = new ResizeObserver(onResize)
  observer.observe(node)
  return () => observer.disconnect()
}, [onResize])

const setRef = useMergedRef(ref, observeRef)

Bu, geri çağırma ref'lerini gözlemciler ve dinleyiciler gibi öğenin yaşam süresine bağlı her şey için iyi bir yer yapar. Kurulum ve sökme birlikte durur ve onları diğer ref'lerle birleştirmek çalışmalarını sürdürür.

useMergedRef(ref, (node) => console.log(node))

const logRef = React.useCallback((node) => console.log(node), [])
useMergedRef(ref, logRef)
  • Birleştirilmiş geri çağırma, herhangi bir ref değiştiğinde değişir. Satır içi bir ok fonksiyonu her işlemede yeni bir ref'tir; bu yüzden React öğeyi her seferinde ayırıp yeniden bağlar. Geri çağırma ref'lerini useCallback ile sarın.
  • undefined ve null ref'ler atlanır; böylece isteğe bağlı prop'ları doğrudan verebilirsiniz.
  • İletilen tek bir ref ve yerel bir nesne ref'i için useComposedRef daha kısadır.
PropTürVarsayılan
...refsNesne ref'leri, geri çağırma ref'leri veya undefined.
Array<Ref<T> | undefined>–
DöndürürAçıklama
(node: T | null) => () => voidÖğenin ref'ine verin. Birleşik temizlemeyi döndürür.

Field ve InputGroup.