React.js Hook’lar ve Kullanımları Part 2
Herkese selam!
Bir önce ki yazımda React hooklarından, en sık kullanılan useState
, useEffect
ve useContext
gibi önemli hookları anlatıp örneklendirmiştim. Bu blog yazısında ise useReducer
, useCallback
, useMemo
, useRef
ve useLayoutEffect
hooklarını basitçe anlatıp örneklendirmeye çalışacağım.
1) useReducer Hook
useState’e benzer bir şekilde state yönetimi için kullanılan bir React hook’u olan useReducar; daha karmaşık state yönetimi gerektiğinde, özellikle state geçişlerinin mantıksal(if’ler ile) şekilde yönetilmesi gerektiğinde tercih edilir. Bu hook, bir işlev ve başlangıç durumu ile birlikte kullanılır. İşlev, mevcut durumu ve bir eylemi alır ve yeni bir durum döndürür.
Örnek olarak, basit bir count yönetimi düşünelim:
import React, { useReducer } from 'react';
// State yönetimi için kullanılacak olan reducer fonksiyonu
// if veya switch ile burada karmaşık bir şekilde state'i güncelleyip return ediyoruz.
const counterReducer = (state, action) => {
switch (action.type) {
case 'INCREMENT':
return { count: state.count + 1 };
case 'DECREMENT':
return { count: state.count - 1 };
default:
return state;
}
};
const Counter = () => {
// useReducer hook'u ile state'i ve state güncellemek için dispatch işlevini alıyoruz.
const [state, dispatch] = useReducer(counterReducer, { count: 0 });
return (
<div>
<p>Count: {state.count}</p>
<button onClick={() => dispatch({ type: 'INCREMENT' })}>Increment</button>
<button onClick={() => dispatch({ type: 'DECREMENT' })}>Decrement</button>
</div>
);
};
export default Counter;
Böylece state güncellerken duruma bağlı bir şekilde komplike bir işlemi basite indirgeyerek useState
yerine useReducer
kullanıyor ve güncelleme işlemini kolaylaştırabiliyoruz.
Kullanımı useState ile benzer olsa da; bir fonksiyon içerisinde birden fazla state set etme kullanmak yerine useReducer kullanarak tek bir switch içerisinde tüm durumları handle etmemize yarıyor.
2) useCallback Hook
React’ta performansı optimize etmek ve gereksiz işlemleri önlemek için kullanılan bir hook’tur. Özellikle fonksiyonların yeniden oluşturulmasını engellemek için kullanılır. Çünkü her fonksiyon oluşturulduğunda, bunun sonucunda component yeniden render edilir. Bu durum, özellikle optimize edilmemiş fonksiyonların kullanıldığı durumlarda gereksiz yere performans kaybına yol açabilir.
useCallback
hook'u, bir fonksiyonu ve bağımlılık(dependency) dizisini alır ve bu işlevi yeniden oluşturmadan sadece bağımlılık dizisindeki değerler değiştiğinde güncellemeyi sağlar.
Örnek olarak, aşağıdaki kodda bir basit bileşen örneği ve kullanımı görülebilir:
import React, { useState, useCallback } from 'react';
const Counter = () => {
const [count, setCount] = useState(0);
{/*
const increment = () => {
setCount(count + 1);
};
*/}
// Bu fonksiyon her render sırasında yeniden oluşturulur bu yüzden bu şekilde
// kullanmak yerine aşağıda ki gibi kullanarak performansdan kazanım sağlarız
// useCallback ile fonksiyonun yeniden oluşturulması engellenir
const incrementCallback = useCallback(() => {
setCount(count + 1);
}, [count]); // count dependency
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment (Normal)</button>
<button onClick={incrementCallback}>Increment (useCallback)</button>
</div>
);
};
export default Counter;
Yukarıdaki örnekte, increment
adlı fonksiyon her render sırasında yeniden oluşturulur ve bu da bahsettiğim gibi gereksiz performans kaybına yol açabilir. Ancak incrementCallback
, useCallback
ile oluşturulduğu için yalnızca count
değiştiğinde/değişeceğinde yeniden oluşturulur. Bu sayede gereksiz renderlerden kaçınılmış olur.
3) useMemo Hook
Hesaplama maliyeti yüksek olan işlemlerin sonuçlarını önbelleğe almak ve gereksiz hesaplamaları önlemek için kullanılan bir React hook’udur. Bu sayede işlemler tekrar tekrar gerçekleştirilmek yerine önbellekte saklanır ve gerektiğinde kullanılır.
useMemo
hook'u, bir hesaplama fonksiyonunu ve bağımlılık dizisini alır. Bağımlılık dizisinde belirtilen değerler değiştiğinde, hesaplama fonksiyonu tekrar çalıştırılır ve sonuç önbelleğe alınır.
Örneğin, bir component içerisinde bir metin alanı ve metnin karakter sayısını gösteren bir uygulama düşünelim. Bu metin alanına girilen metin her değiştiğinde, karakter sayısını hesaplamak yerine useMemo
ile önbelleğe alabiliriz.
import React, { useState, useMemo } from 'react';
const CharacterCount = () => {
const [text, setText] = useState('');
// useMemo ile karakter sayısı hesaplaması önbelleğe alınır
const charCount = useMemo(() => {
return text.length;
}, [text]);
return (
<div>
<textarea
value={text}
onChange={event => setText(event.target.value)}
rows={4}
cols={50}
/>
<p>Character Count: {charCount}</p>
</div>
);
};
export default CharacterCount;
useMemo
kullanarak metin her değiştiğinde sadece gerekli hesaplamalar yapılır ve gereksiz renderlerin ve hesaplamaların önüne geçilir.
4) useRef Hook
React bileşenlerinde DOM öğelerine veya diğer değerlere doğrudan erişmek ve bu değerlerin değişikliklerini izlemek için kullanılan bir hook’tur. useRef
, genellikle componentlerin yaşam döngüsüyle ilişkili olmayan verileri saklamak veya DOM işlemleri gerçekleştirmek için kullanılır.
useRef
hook'u, bir nesne döndürür ve bu nesne current
özelliği altında geçerli değeri saklar. Bu değer değişse bile bileşen yeniden render edilmez.
Örnek olarak, bir metin alanını temizlemek için useRef
kullanabiliriz:
import React, { useRef, useState } from 'react';
const ClearableInput = () => {
const inputRef = useRef(null);
const [text, setText] = useState('');
const clearInput = () => {
setText('');
inputRef.current.value = '';
inputRef.current.focus();
};
return (
<div>
<input
type="text"
ref={inputRef}
value={text}
onChange={event => setText(event.target.value)}
/>
<button onClick={clearInput}>Clear</button>
</div>
);
};
export default ClearableInput;
Bu örnekte, useRef
ile bir metin girişi öğesine erişiyoruz. Ardından, clearInput
işlevi içinde bu referansı kullanarak metin girişini temizliyoruz ve focusluyoruz. useRef
burada DOM öğelerine doğrudan erişmemizi sağladığından focus işlemini gerçekleştirebiliyoruz.
5) useLayoutEffect Hook
useEffect
hook'u gibi çalışırken, tarayıcıdaki düzen (layout) aşamasından hemen önce çalışan bir React hook'udur. Yani, useLayoutEffect
ile yaptığınız işlemler, DOM güncellemeleri tamamlandıktan sonra, ancak tarayıcıdaki yeniden düzenleme (layout) aşamasından önce gerçekleştirilir. Bu, genellikle kullanıcı arayüzüne etki eden işlemler için kullanılır.
Birçok durumda, useLayoutEffect
yerine useEffect
kullanmanız önerilir. Ancak bazı durumlarda, işlemlerin düzen (layout) aşamasından önce yapılması gerekebilir. Örneğin, DOM ölçümleri almak veya bazı animasyon işlemleri yapmak istediğinizde useLayoutEffect
kullanılabilir.
Örnek olarak, bir bileşenin yüksekliğini ölçüp bu yüksekliği bir state’e kaydetmek için useLayoutEffect
kullanabiliriz:
import React, { useLayoutEffect, useState, useRef } from 'react';
const HeightTracker = () => {
const [height, setHeight] = useState(0);
const elementRef = useRef(null);
useLayoutEffect(() => {
setHeight(elementRef.current.clientHeight);
}, []);
return (
<div>
<div ref={elementRef} style={{ background: 'lightgray', padding: '10px' }}>
Bu bir metin öğesidir.
</div>
<p>Yükseklik: {height}px</p>
</div>
);
};
export default HeightTracker;
Bu örnekte, useLayoutEffect
kullanarak bir DOM öğesinin yüksekliğini ölçüyoruz. Bu ölçüm işlemi, component render edildikten sonra gerçekleşir ve ölçüm sonucu component state’ine kaydedilir. Bu, bileşenin yeniden düzenlenmesi (layout) aşamasından önce gerçekleştirildiği için useLayoutEffect
kullanılması uygundur.