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 veref
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 deref
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 iletilenref
özelliği nesne veya fonksiyon olabilir. Eğer üst bileşen birref
iletmemişse, bu değernull
olur. Aldığınızref
’i başka bir bileşene ya dauseImperativeHandle
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şenref
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.
Ö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>
);
});