forwardRef
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 verefile ç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,forwardRefile döndürülen bileşen derefprop’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 iletilenrefözelliği nesne veya fonksiyon olabilir. Eğer üst bileşen birrefiletmemişse, bu değernullolur. Aldığınızref’i başka bir bileşene ya dauseImperativeHandlefonksiyonuna 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,forwardReftarafından döndürülen bileşenrefprop’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.
Ö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.
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>
);
});