forwardRef, bileşeninizin bir DOM elemanını, üst bileşene ref (referans) ile iletmenize olanak sağlar.

const SomeComponent = forwardRef(render)

Referans

forwardRef(render)

Bileşeninizin bir ref alması ve bunu alt bileşene iletmesi için forwardRef()’i çağırın:

import { forwardRef } from 'react';

const MyInput = forwardRef(function MyInput(props, ref) {
// ...
});

Daha fazla örnek için aşağıya bakınız.

Parametreler

  • render: Bileşeniniz için render fonksiyonu. React, bu fonksiyonu üst bileşenden aldığı props ve ref ile çağırır. Döndürdüğünüz JSX, bileşeninizin çıktısı olacaktır.

Döndürülen değer

  • forwardRef, JSX’te render edebileceğiniz bir React bileşeni döndürür. Düz fonksiyonlar olarak tanımlanan React bileşenlerinin aksine, forwardRef ile döndürülen bileşen de ref prop’u da bulunur.

Uyarılar

  • Katı Mod (Strict Mode) ile, React render fonksiyonunuzu iki kez çağırarak istemeden yapılan hataları bulmanızı kolaylaştırır. Bu, yalnızca geliştirme ortamı davranışıdır ve canlı ortamı etkilemez. Eğer render fonksiyonunuz saf (olması gerektiği gibi) ise, bu bileşenin işleyişine zarar vermemelidir. Çağrılardan birinin sonucu göz ardı edilecektir.

render fonksiyonu

forwardRef, render fonksiyonunu argüman olarak kabul eder. React, bu fonksiyonu props ve ref ile çağırır:

const MyInput = forwardRef(function MyInput(props, ref) {
return (
<label>
{props.label}
<input ref={ref} />
</label>
);
});

Parametreler

  • props: Üst bileşen tarafından iletilen proplar.

  • ref: Üst bileşenden iletilen ref özelliği nesne veya fonksiyon olabilir. Eğer üst bileşen bir ref iletmemişse, bu değer null olur. Aldığınız ref’i başka bir bileşene ya da useImperativeHandle fonksiyonuna aktarmanız gerekir.

Döndürülen değer

  • forwardRef, JSX’te render edebileceğiniz bir React bileşeni döndürür. Düz fonksiyonlar olarak tanımlanan React bileşenlerinin aksine, forwardRef tarafından döndürülen bileşen ref prop’u alabilir.

Kullanım

Üst bileşene DOM erişimi sağlama

Her bileşenin DOM elemanları varsayılan olarak özeldir. Ancak, bazen bir DOM elemanını üst bileşene erişilebilir kılmak yararlı olabilir; örneğin, odaklanma (focus) sağlamak amacıyla. Bunu yapmak için, bileşen tanımınızı forwardRef() ile sarmalayarak kullanın:

import { forwardRef } from 'react';

const MyInput = forwardRef(function MyInput(props, ref) {
const { label, ...otherProps } = props;
return (
<label>
{label}
<input {...otherProps} />
</label>
);
});

Props’tan sonra ikinci argüman olarak bir ref alacaksınız. Üst bileşenin erişim sağlamasını istediğiniz DOM elemanına bu ref’i aktarın:

import { forwardRef } from 'react';

const MyInput = forwardRef(function MyInput(props, ref) {
const { label, ...otherProps } = props;
return (
<label>
{label}
<input {...otherProps} ref={ref} />
</label>
);
});

Üst Form bileşeninin, MyInput tarafından sağlanan <input> DOM elemanına erişimine izin verir:

function Form() {
const ref = useRef(null);

function handleClick() {
ref.current.focus();
}

return (
<form>
<MyInput label="Enter your name:" ref={ref} />
<button type="button" onClick={handleClick}>
Edit
</button>
</form>
);
}

Bu Form bileşeni, MyInput’a bir ref gönderir. MyInput bileşeni, bu ref’i tarayıcıdaki <input> etiketine iletir. Sonuç olarak, Form bileşeni, <input> DOM elemanına erişebilir ve üzerinde focus() işlemini çağırabilir.

Unutmayın ki, bileşeninizin içindeki DOM elemanına bir ref sağlamak, daha sonra bileşeninizin iç yapısını değiştirmeyi zorlaştırır. Genellikle, butonlar (<button>) veya metin girişleri (<input>) gibi yeniden kullanılabilir temel bileşenlerden DOM elemanları sağlarsınız, ancak bunu avatar veya yorum gibi uygulama seviyesi bileşenler için yapmamalısınız.

Examples of forwarding a ref

Örnek 1 / 2:
<input> elamanına odaklanma (focus)

Bu kod parçasında, <button> elemanına tıklanınca <input>’a odaklanılıyor. Form bileşeni, bir ref tanımlayarak MyInput bileşenine iletiyor. MyInput bileşeni, tanımlanan ref’i tarayıcının <input> etiketine aktarıyor. Böylece Form bileşeni, <input> üzerinde odaklanabilir hale geliyor.

import { useRef } from 'react';
import MyInput from './MyInput.js';

export default function Form() {
  const ref = useRef(null);

  function handleClick() {
    ref.current.focus();
  }

  return (
    <form>
      <MyInput label="Enter your name:" ref={ref} />
      <button type="button" onClick={handleClick}>
        Edit
      </button>
    </form>
  );
}


Birden fazla bileşen aracılığıyla ref iletmek

Bir DOM elemanına ref aktarmak yerine, MyInput gibi kendi bileşeninize aktarabilirsiniz:

const FormField = forwardRef(function FormField(props, ref) {
// ...
return (
<>
<MyInput ref={ref} />
...
</>
);
});

Eğer MyInput bileşeni, <input> elemanına ref’i aktarırsa, FormField bileşeninden gönderilen ref, o <input> elemanına erişmenizi sağlar.

function Form() {
const ref = useRef(null);

function handleClick() {
ref.current.focus();
}

return (
<form>
<FormField label="Enter your name:" ref={ref} isRequired={true} />
<button type="button" onClick={handleClick}>
Edit
</button>
</form>
);
}

Aşağıdaki kod parçasında, Form bileşeni bir ref tanımlar ve FormField’e iletir. FormField bileşeni, ref’i MyInput’a ileterek tarayıcıdaki <input> DOM elemanına erişim sağlar. Bu sayede Form bileşeni, istenilen DOM elemanına erişebilir.

import { useRef } from 'react';
import FormField from './FormField.js';

export default function Form() {
  const ref = useRef(null);

  function handleClick() {
    ref.current.focus();
  }

  return (
    <form>
      <FormField label="Enter your name:" ref={ref} isRequired={true} />
      <button type="button" onClick={handleClick}>
        Edit
      </button>
    </form>
  );
}


DOM elemanı yerine, kontrolör (imperative handle) kullanma.

Tüm DOM elemanlarını erişime açmak yerine, daha kısıtlı yöntem setine sahip özel bir nesne olan kontrolör (imperative handle) kullanabilirsiniz. Bu işlem için, DOM elemanını belirtmek amaçlı ayrı bir ref tanımlamanız gereklidir:

const MyInput = forwardRef(function MyInput(props, ref) {
const inputRef = useRef(null);

// ...

return <input {...props} ref={inputRef} />;
});

Aldığınız ref’i useImperativeHandle fonksiyonuna iletin ve erişilmesini istediğiniz değeri verin:

import { forwardRef, useRef, useImperativeHandle } from 'react';

const MyInput = forwardRef(function MyInput(props, ref) {
const inputRef = useRef(null);

useImperativeHandle(ref, () => {
return {
focus() {
inputRef.current.focus();
},
scrollIntoView() {
inputRef.current.scrollIntoView();
},
};
}, []);

return <input {...props} ref={inputRef} />;
});

Bir bileşen MyInput üzerinden ref’e erişmek istediğinde, DOM elemanı yerine {focus, scrollIntoView} nesnesini elde eder. Bu sayede, DOM elemanı hakkında paylaşılan bilgi minimum düzeyde tutulabilir.

import { useRef } from 'react';
import MyInput from './MyInput.js';

export default function Form() {
  const ref = useRef(null);

  function handleClick() {
    ref.current.focus();
    // Bu çalışmayacak çünkü DOM elemanı erişilebilir değil:
    // ref.current.style.opacity = 0.5;
  }

  return (
    <form>
      <MyInput placeholder="Enter your name" ref={ref} />
      <button type="button" onClick={handleClick}>
        Edit
      </button>
    </form>
  );
}

Kontrolör (imperative handle) hakkında daha fazla bilgi edinin.

Tuzak

Ref’leri aşırı kullanmaktan kaçınmalısınız. Yalnızca prop’lar ile ifade edilemeyen zorunlu davranışlar için kullanmalısınız. Örneğin, bir DOM elemanında kaydırma, odaklama, animasyon tetikleme veya metin seçme gibi işlemler için.

Bir şeyi bir prop olarak ifade edebiliyorsanız, ref kullanmamalısınız. Örneğin, bir Modal bileşeninde { open, close } gibi kontrolör (imperative handle) oluşturmak yerine, isOpen prop’unu <Modal isOpen={isOpen} /> şeklinde kullanmak daha iyidir. Efektler, kontrollü davranışları prop’lar aracılığıyla sağlamanıza yardımcı olabilir.


Sorun Giderme

Bileşenim forwardRef ile sarılı ama ref değeri sürekli null oluyor.

Bu, genellikle aldığınız ref’i kullanmayı unuttuğunuz anlamına gelir.

Örneğin, bu bileşen aldığı ref’i hiçbir şekilde kullanmamaktadır:

const MyInput = forwardRef(function MyInput({ label }, ref) {
return (
<label>
{label}
<input />
</label>
);
});

Bu problemi çözmek adına, ref’i bir DOM elementine veya ref alabilen başka bir bileşene iletmelisiniz.

const MyInput = forwardRef(function MyInput({ label }, ref) {
return (
<label>
{label}
<input ref={ref} />
</label>
);
});

Eğer belirli koşullara bağlı olarak işlemler yapılıyorsa, MyInput bileşenine atanan ref değeri null olabilir.

const MyInput = forwardRef(function MyInput({ label, showInput }, ref) {
return (
<label>
{label}
{showInput && <input ref={ref} />}
</label>
);
});

Eğer showInput değeri false olursa, ref hiçbir elemana iletilmeyecek ve MyInput bileşenine atanan ref boş olacaktır. Özellikle, eğer bu durum bir bileşenin içinde saklanıyorsa, örneğin bu örnekteki Panel gibi, bu durum kolaylıkla gözden kaçabilir:

const MyInput = forwardRef(function MyInput({ label, showInput }, ref) {
return (
<label>
{label}
<Panel isExpanded={showInput}>
<input ref={ref} />
</Panel>
</label>
);
});