React Hooks ile Custom Hook Yazma
Aynı useState + useEffect kombinasyonunu üçüncü kez yazdığınızı fark ettiyseniz, ortada bir custom hook fırsatı var. React'te tekrar kullanılabilir mantığı paylaşmanın yolu bileşen değil, hook'tur. Görsel çıktı üretmeyen ama durum tutan, veri çeken, olay dinleyen her şey bir react custom hook içine taşınabilir.
İyi haber: sihir yok. Custom hook, adı use ile başlayan ve içinde başka hook'lar çağırabilen sıradan bir JavaScript fonksiyonudur. Bu yazıda önce kuralları ve anatomiyi kuruyoruz, sonra kendi başınıza yazabileceğiniz üç pratik hook'u adım adım çıkarıyoruz.
Custom Hook'un Anatomisi ve Kuralları
Hook yazmaya başlamadan önce React'in size koyduğu iki sınırı içselleştirmek gerekiyor. Bu sınırlar keyfi değil; React, hook çağrılarını çağrı sırasına göre eşleştirdiği için var.
İsimlendirme ve çağrı sırası
- Fonksiyon adı use ile başlamalı. Bu sadece stil değil; ESLint kuralları ve React DevTools bu ön eke bakar.
- Hook'lar yalnızca bileşenlerin veya başka hook'ların en üst seviyesinde çağrılır. if, for veya try bloğu içinde çağırmayın.
- Koşullu davranış gerekiyorsa hook'u her zaman çağırın, koşulu hook'un içinde işletin. Örneğin veri çekme hook'una enabled parametresi verip effect içinde erken çıkın.
- Eslint eklentisi olarak eslint-plugin-react-hooks kurun. Bağımlılık dizisi hatalarını sizin yerinize yakalar.
Ne döndürmeli?
Dönüş tipi, hook'un kullanım rahatlığını doğrudan belirler:
- Dizi döndürün: iki-üç değer varsa ve kullanıcı isimleri kendi belirlemek isteyecekse. useState mantığı.
- Nesne döndürün: üçten fazla değer varsa veya bazıları opsiyonel kullanılacaksa. Okur, data, error, loading gibi anlamlı isimleri kaybetmez.
- Döndürdüğünüz fonksiyonları useCallback ile sarın. Aksi halde her render'da yeni referans üretir ve tüketen effect'leri boşuna tetiklersiniz.
- Tek bir sorumluluk taşısın. "Kullanıcıyı çek, formu doğrula ve modalı yönet" yapan bir hook, bakımı en zor koddur.
Durum paylaşılmaz, mantık paylaşılır
En sık yanılgı bu: aynı hook'u iki bileşende kullanmak, durumu ortaklaştırmaz. Her çağrı kendi bağımsız state'ini kurar. Gerçekten ortak durum istiyorsanız Context veya bir store devreye girer; hook o zaman Context'i okuyan ince bir katmana dönüşür.
Sıfırdan Üç Hook Yazalım
Aşağıdaki üçünü sırayla yazmanızı öneririm. Zorluk artıyor ve her biri bir önceki dersi pekiştiriyor.
1. useLocalStorage — senkron başlangıç değeri
Amaç: state'i tutmak ama tarayıcı depolamasıyla senkron kalmak.
- Parametre olarak key ve initialValue alın.
- useState çağrısına doğrudan değer değil, fonksiyon verin. Böylece depolama okuma işlemi yalnızca ilk render'da çalışır.
- Okuma işlemini try/catch içine alın. Bozuk JSON veya kapatılmış depolama uygulamayı düşürmesin.
- Sarmalayıcı bir setValue yazın: gelen değer fonksiyonsa önce mevcut state ile çalıştırın, sonra hem state'i hem depolamayı güncelleyin.
- [value, setValue] dizisini döndürün.
Tuzak: değeri effect içinde yazmak da işe yarar ama iki render arasında tutarsızlık penceresi açar. Yazma işini setter'ın içinde yapmak daha öngörülebilir.
2. useDebounce — zamanlayıcı temizliği
Arama kutuları için klasik. Öğrettiği şey cleanup disiplini.
- value ve delay alın, iç state'i başlangıçta value ile kurun.
- Bir effect açın; içinde setTimeout ile state'i gecikmeli güncelleyin.
- Effect'ten mutlaka bir temizleme fonksiyonu döndürün ve clearTimeout çağırın. Bu satır olmazsa her tuş vuruşu birikir.
- Bağımlılıklara [value, delay] yazın ve sadece gecikmiş değeri döndürün.
Bunu bir API isteğiyle birleştirdiğinizde ağ trafiğindeki düşüşü DevTools'un Network sekmesinde çıplak gözle görürsünüz. JavaScript performans ipuçlarında geçen "gereksiz işi yapmama" prensibinin en somut hali.
3. useFetch — yarış koşulu ve iptal
Veri çekme hook'u basit görünür, gerçekte en çok tuzak barındıran örnektir.
- State olarak data, error, loading tutun. Tek bir nesne halinde tutmak üç ayrı setter çağrısından temizdir.
- Effect başında AbortController oluşturun, signal'i isteğe geçirin.
- Cleanup içinde abort çağırın. Kullanıcı URL'yi hızlıca değiştirdiğinde eski yanıt yeni yanıtı ezmez.
- Yanıt gelmeden bileşen söküldüyse state güncellemeyin; iptal edilen istekte hata tipini ayırt edip sessizce çıkın.
- HTTP durum kodunu kontrol etmeyi atlamayın. fetch, 404'te reject etmez.
- Manuel yenileme için bir refetch fonksiyonu döndürün.
| Hook | Öğrettiği kavram | Ana tuzak |
|---|---|---|
| useLocalStorage |