HextaUI

useComposedRef

Mantém uma ref para o seu próprio elemento e, ao mesmo tempo, a encaminha para qualquer ref que o pai tenha passado.

"use client"

import * as React from "react"

import { Button } from "@/components/ui/button"
import { useComposedRef } from "@/hooks/use-composed-ref"

function CharacterInput({ ref, ...props }: React.ComponentProps<"input">) {
  const [inputRef, setRef] = useComposedRef<HTMLInputElement>(ref)
  const [length, setLength] = React.useState(0)

  return (
    <div className="flex h-9 w-full items-center gap-2 rounded-md bg-muted pe-3 focus-within:ring-3 focus-within:ring-focus-ring">
      <input
        ref={setRef}
        {...props}
        onChange={(event) => {
          props.onChange?.(event)
          setLength(event.target.value.length)
        }}
        className="h-full min-w-0 flex-1 bg-transparent ps-3 text-sm outline-none focus-visible:outline-hidden pointer-coarse:text-touch"
      />
      <button
        type="button"
        hidden={length === 0}
        onClick={() => {
          const input = inputRef.current
          if (input) {
            input.value = ""
            setLength(0)
            input.focus()
          }
        }}
        className="text-xs text-muted-foreground hover:text-foreground"
      >
        Clear
      </button>
    </div>
  )
}

export function UseComposedRefDemo() {
  const ref = React.useRef<HTMLInputElement>(null)

  return (
    <div className="flex w-full max-w-xs flex-col gap-3">
      <CharacterInput ref={ref} aria-label="Search" placeholder="Search" />
      <Button variant="outline" size="sm" onClick={() => ref.current?.focus()}>
        Focus from the parent
      </Button>
    </div>
  )
}
pnpm dlx shadcn@latest add https://hextaui.com/r/use-composed-ref.json

Adiciona o hook e tudo de que ele depende ao seu projeto.

import { useComposedRef } from "@/hooks/use-composed-ref"
function SearchInput({ ref, ...props }: React.ComponentProps<"input">) {
  const [inputRef, setRef] = useComposedRef<HTMLInputElement>(ref)

  React.useEffect(() => {
    inputRef.current?.select()
  }, [inputRef])

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

No React 19, ref é uma prop comum. Quando seu componente também precisa do elemento para si, você tem duas refs e apenas um atributo ref. Este hook dá a você uma ref de objeto para ler, mais um callback que preenche as duas refs.

function SearchInput({ ref, ...props }: React.ComponentProps<"input">) {
  const inputRef = React.useRef<HTMLInputElement>(null)
  return <input ref={inputRef} {...props} />
}

Isto compila, mas a ref do pai é descartada, então ref.current permanece null no pai. Com useComposedRef, tanto o pai quanto o componente recebem o elemento.

  • O inputRef retornado é um RefObject normal, então você pode passá-lo a hooks que esperam um, como useAutosize ou useInvalidShake.
  • setRef mantém a mesma identidade enquanto a ref do pai a mantém, então o React não a desanexa e reanexa a cada renderização.
  • Funciona com refs de objeto, refs de callback e sem ref alguma.

Use useComposedRef quando combinar exatamente uma ref repassada com sua própria ref de objeto, que é o caso da maioria dos componentes. Use useMergedRef quando combinar mais de duas, quando uma delas for uma ref de callback de outro hook, ou quando uma ref de callback repassada retornar uma função de cleanup do React 19. useComposedRef chama uma ref de callback com null ao desanexar em vez de executar seu cleanup.

PropTipoPadrão
refA ref que seu componente recebeu.
Ref<T> | undefined–
RetornaDescrição
[0] RefObject<T | null>Sua própria ref para o elemento.
[1] (node: T | null) => voidPasse para a ref do elemento. Preenche as duas refs.

Input, Textarea, NativeSelect, Field e InputGroup.