React tarafında dosya işi, ilk bakışta “bir input koyarız, biter” gibi duruyor. Gerçekten öyle düşünüyorsunuz başta (en azından benim deneyimim böyle). Ama iş avatar yüklemeye, CSV içeri aktarmaya, sürükle-bırak alanına ve önizleme üretmeye gelince tablo bir anda değişiyor — hem de nasıl değişiyor. Geçen ay İstanbul’da bir müşteri (söylemesi ayıp) projesinde tam bunu yaşadım; ekip “küçük bir upload ekranı” diyordu, iki gün sonra hidden input’lar, temizlenmeyen seçmeler ve bellekte dolaşan object URL’ler arasında kaybolmuştuk hani. Küçük görünen işler vardır ya…
Açıkçası, İşte bu onlardan biri.
Asıl mesele şu: tarayıcıda dosya yönetimi üç farklı API’nin el sıkışmasıyla yürüyor. Bir yanda <input type="file">, bir yanda Drag and Drop API, öbür tarafta da URL.createObjectURL. React ise üstüne kendi ref ve effect mantığını ekliyor — ve bu katmanlar ilk kez bir araya geldiğinde her şey yolunda gidiyor gibi görünür… ta ki aynı bileşeni ikinci kez kullanana kadar.
Neden Dosya İşleri Hep Dağılır?
İlginç olan şu ki, Bir startup’ta çalışırken bunun ne kadar can sıkıcı olduğunu çok daha net görüyorsunuz (kendi tecrübem). Tasarımcı “sadece güzel bir buton olsun” diyor, backend ekibi “dosya boyutu limiti koyun” diye bastırıyor, ürün tarafı ise “telefonla çekilen fotoğraf da kabul etsin” diye ekliyor — ve derken o basit görünen ekran, üç farklı edge case’in tam ortasında kalakalıyor.
2023’te Ankara’daki bir SaaS panelinde benzer bir yapı kurmuştum. En büyük sürpriz dosyayı yeniden seçince change event’inin tetiklenmemesiydi. Açık konuşayım: bu durum insanı sinirlendiriyor. Kullanıcı aynı fotoğrafı tekrar seçtiğinde sistemin sessiz kalması bayağı garip duruyor — küçük ama sinir bozucu bir detay.
Bir de güvenlik tarafı var. Tarayıcı size dosyanın tamamını vermez; sadece erişime izin verdiği ölçüde davranır. Bu yüzden “ben bunu state’e atarım olur biter” yaklaşımı bazen idare eder ama ölçek büyüyünce yetmez. Kurumsal projede ayrı dert, küçük ekipte ayrı dert…
En çok nerede patlıyor?
Klasik sorunlar aslında hep aynı: gizli input’un stil karmaşası yaratması, aynı dosyanın ikinci seçimde yakalanmaması, preview için oluşturulan object URL’in unutulup bellek sızıntısı yapması ve drop zone alanının bazı tarayıcılarda beklenmedik davranması. Yani zincirin her halkası ayrı nazlı, ayrı kırılgan.
- Kullanıcı deneyimi: Dosya seçici doğal hissettirmiyor olabilir.
- Bellek: Object URL’ler temizlenmezse gereksiz yük bırakır.
- Sürdürülebilirlik: Aynı mantığı her sayfada yeniden yazmak yoruyor.
Dosya Seçme: Gizli Input Mu, Akıllı Hook Mu?
Şunu fark ettim: Klasik yöntem hâlâ yaygın. Görünmeyen bir input koyarsınız, butona basınca ref ile click tetiklersiniz. Çalışır mı? Çalışır. Peki zarif mi? Eh… çok değil. Bilhassa aynı sayfada iki farklı yükleyici varsa ref karmaşası hemen başlıyor.
Çok konuştum, örnekle göstereyim.
Bilmem anlatabiliyor muyum, Bunu test ettiğimde — geçen hafta Kadıköy’deki masamda, evet biraz da alışkanlık bu — en çok gözüme batan şey reset işlemi oldu. inputRef.current.value = "" yazıp geçiyorsunuz ama bu ufak müdahale React’in ruhuna pek uygun hissettirmiyor. Siz ne dersiniz? İşi yapıyor, tamam, ama el yordamıyla yapılmış gibi duruyor — ve orta vadede bu his çoğunlukla haklı çıkıyor (ciddiyim) Freelance Pazarındaki Kargaşa Bitiyor mu?: Assignly Ne Vadediyor yazımızda bu konuya da değinmiştik.
import { useRef, useState } from "react";
function ManualFilePicker() {
const inputRef = useRef(null);
const [files, setFiles] = useState(null);
return (
<input
ref={inputRef}
type="file"
multiple
accept="image/*"
style={{ display: "none" }}
onChange={(e) => setFiles(e.target.files)}
/>
<button onClick={() => inputRef.current?.click()}>
Resim Seç
</button>
{files && {files.length} dosya seçildi
}
);
}
Daha temiz tarafta iş biraz rahatlıyor. Özel hook kullanınca tam — ki bu tartışılır — olarak ne aldığınızı biliyorsunuz: dosyalar, açma fonksiyonu ve sıfırlama işlemi. Güzel olan şu; render ağacında gizli input taşıma derdiniz azalıyor. Kötü tarafı? Kütüphaneye bağımlılık artıyor tabi, bunu görmezden gelmeyelim.
Bir dakika — bununla bitmedi. Daha fazla bilgi için Java’da BFS: Kuyrukla Gelen Temiz Geçiş Rehberi yazımıza bakabilirsiniz.
Küçük ekipte mi büyük kurumda mı?
| Senaryo | Manuel yaklaşım | Hook tabanlı yaklaşım |
|---|---|---|
| Küçük startup | Daha hızlı başlatılır | Daha az bakım yükü verir |
| Enterprise seviye | Zamanla teknik borç çıkarır | Standartlaşmayı kolaylaştırır |
Tuhaf ama, Açık konuşayım: başlangıçta manuel çözüm cazip geliyor. Ekstra bağımlılık istemiyorsunuz — mantıklı da aslında. Ama ekip büyüdüğünde veya aynı desen birkaç yerde tekrarlandığında hook tabanlı çözüm çok daha az baş ağrıtıyor. Bunu deneyimledim, lafı gevelemenin anlamı yok (buna dikkat edin)
Sürükle-Bırak Alanı Kurarken Dikkat Edilecekler
Sürükle-bırak kısmı da ilk bakışta havalı duruyor. Gerçekten duruyor. Ama altından yine epey detay çıkıyor — kullanıcı dosyayı alanın üstüne getirdiğinde görsel geri bildirim vermek gerekiyor; yoksa insanlar alanın aktif olup olmadığını anlamıyor, boşlukta bırakıyorlar dosyayı.
Hani, Ben buna ilk kez İzmir’deki bir e-ticaret panelinde takılmıştım. Tasarım şahane görünüyordu ama hover state olmayınca kullanıcılar nereye bırakacağını kestiremiyordu. Basit. Çözülmesi de basit. Ama fark etmek zaman alıyor işte.
İnanın, Eğer sadece temel HTML5 drag events ile ilerlerseniz olay kısa sürede karışabiliyor: dragover engeli gerekiyor, drop anında default davranışı iptal etmek gerekiyor, kabul edilen türleri filtrelemek gerekiyor… liste uzar gider. İşin aslı şu ki burada amaç kahramanlık yapmak değil; okunabilir, sürdürülebilir bir akış kurmak. BFF Nedir? Frontend İçin Akıllı Orta Katman Rehberi yazımızda bu konuya da değinmiştik.
Neyi iyi yapmalı?
– Görsel sınırı belli olmalı.
– Dosya türü kullanıcıya önceden anlatılmalı.
– Mobil tarafta alternatif yol bırakılmalı.
– Hatalar sessizce değil açıkça gösterilmeli.
Sürükle-bırak güzel özellik ama tek başına yeterli değil; özellikle mobil cihazlarda insanlar çoğu zaman dokunarak seçim yapıyor.
E tabi burada performans meselesi de var. Büyük dosyaları anında okumaya kalkarsanız arayüz kasabiliyor — o yüzden mümkünse sadece gerekli metadata’yı alın (yanlış duymadınız). Geri kalan işi arka planda yürütün. Kulağa basit geliyor, pratikte bazen unutuluyor.
Peki Önizleme Neden Object URL ile Yapılıyor?
Bi saniye — Burası benim favori noktalardan biri. Küçük görünüyor ama etkisi büyük. Fotoğraf yükleyen uygulamada kullanıcı önce sonucu görmek istiyor — yani “acaba doğru resmi mi seçtim?” sorusunun cevabı lazım, hemen orada, beklemeden. 2026’nın Viral AI Sanat Trendleri: Prompt Yazmanın İncelikleri yazımızda da bu konuya değinmiştik. SQLite’ı Bırakıp Rust Veritabanına Geçince Ne Değişti? yazımızda da bu konuya değinmiştik.
URL.createObjectURL(file), tarayıcı içinde geçici bir adres üretip dosyayı önizleme için sunuyor. Mantık olarak pratik; file okuyup base64’e çevirmekten daha hafif hissediliyor çoğu senaryoda, özellikle büyük görsellerde bu fark belirginleşiyor. Ama ücretsiz öğle yemeği yok tabi — oluşturduğunuz URL’i sonradan temizlemezseniz bellek tarafında iz bırakıyor, bırakmaya devam ediyor.
Bunu geçen yıl Berlin’de yaptığım yan projede net gördüm; yüzlerce resim önizlenince cleanup unutulursa sekme zamanla hantallaşıyordu. Dramatik bir çöküş değil, ama o yavaşlama hissi var ya… işte tam o.
Tiny cleanup rehberi
useEffect(() => {
if (!file) return;
const previewUrl = URL.createObjectURL(file);
setPreview(previewUrl);
return () => {
URL.revokeObjectURL(previewUrl);
};
}, [file]);
Kod kısa ama mesaj net. Oluşturduğunu geri vermezsen fatura çıkar — tarayıcı bunu söylemiyor ama hissettiriyor zamanla. Preview hayat kurtarıyor olsa da temizliği atlamak büyük hata.
Dördünü Bir Araya Getirince Ne Oluyor?
Asıl değer parçaları birlikte düşününce ortaya çıkıyor (kendi tecrübem). Bir fotoğraf yükleyici düşünün: kullanıcı ister düğmeye basıp dosya seçsin ister sürükleyip bıraksın, hemen önizlemeyi görsün ve gerekiyorsa dış kütüphane sadece o anda yüklensin — bu akış hem kullanıcı açısından temiz hem de bundle boyutu açısından makul.
Bakın, burayı atlarsanız yazının kalanı anlamsız kalır.
Böyle bir yapı özellikle performans açısından fena değil, hatta bayağı iş görüyor,. Başlangıç bundle’ını şişirmiyorsunuz. Mesela crop veya image processing için ağır bir kütüphane gerekiyorsa bunu yalnızca ihtiyaç olduğunda çağırabilirsiniz. Baştan yüklemek zorunda değilsiniz.
- Select path: Butonla seçim yapar. (bu kritik)
- Drop path: Dosyayı alana bırakır.
- Preview path: Anında görüntüler.
- Processing path: Gerekirse harici araçları sonradan yükler. (bence en önemlisi)
Aynı mantığı LoanLink projesine benzer şekilde kurmuş olsaydım muhtemelen daha erken rahat ederdim (buna dikkat edin). Çünkü o tarz panellerde herkes başka yerden küçük özellik eklemek istiyor ve sonunda kod tabanı minik yamalarla dolup taşıyor. Bir dakika, şunu da ekleyeyim: bu yapı enterprise tarafta standartlaştırılırsa destek maliyeti ciddi düşüyor — bunu rakamla görmeden inanmak zor ama göründüğünde çok net oluyor.
Nerede hayal kırıklığı yaşadım?
Beni en çok şaşırtan şey şu oldu: bazı ekipler hook kullandıkları halde cleanup disiplinini yine kaçırıyor. Araç değişmiş ama alışkanlık değişmemiş. Beklediğim kadar değildi açıkçası. En çok da medya ağırlıklı uygulamalarda bu nokta kritik — ve maalesef hâlâ gözden kaçıyor.
Sıkça Sorulan Sorular::React’te aynı dosyanın tekrar seçilmesi neden algılanmıyor?
Bu içerik işinize yaradı mı?
Benzer içerikleri kaçırmamak için beni sosyal medyada takip edin.



