Gereksinimler ve Ön Hazırlık
Bu projeyi hayata geçirmek için bilgisayarınızda Node.js'in güncel bir sürümünün (LTS) yüklü olması gerekir. Projenizi oluştururken Vite gibi hızlı yapılandırma araçlarını tercih etmeniz önerilir. İhtiyacımız olan temel kütüphane React'in kendisidir ancak dosya işleme süreçlerinde state (durum) yönetimi için useState ve useEffect kancalarını yoğun bir şekilde kullanacağız.
Başlamadan önce terminalinizde şu komutla yeni bir React projesi oluşturabilirsiniz:
npm create vite@latest dosya-yukleme-app -- --template react
cd dosya-yukleme-app
npm install
Bu kurulum, temiz ve hızlı bir geliştirme ortamı sunar. Projenin bağımlılıklarını yükledikten sonra bileşen yapımızı oluşturmaya başlayabiliriz.
Dosya Seçimi ve State Yönetimi
Çoklu dosya yükleme işleminin ilk adımı, HTML input etiketini multiple özelliği ile yapılandırmaktır. React'te bu işlemi yönetirken, seçilen dosyaları bir dizi (array) olarak state içerisinde tutmak en verimli yöntemdir.
import { useState } from 'react';
const FileUploader = () => {
const [files, setFiles] = useState([]);
const handleFileChange = (event) => {
const selectedFiles = Array.from(event.target.files);
setFiles(selectedFiles);
};
return (
);
};
Burada Array.from() kullanarak FileList nesnesini standart bir JavaScript dizisine dönüştürüyoruz. Bu, dosyalar üzerinde map veya filter gibi dizi metotlarını kullanabilmemizi sağlar.
Seçilen Dosyaların Önizlenmesi
Kullanıcıların yükledikleri dosyaları görmeleri, hata payını düşürür. Özellikle resim dosyaları için URL.createObjectURL metodunu kullanarak geçici bir önizleme URL'i oluşturabiliriz. Bu işlem, dosyayı sunucuya göndermeden önce istemci tarafında görmenizi sağlar.
const FilePreview = ({ files }) => {
return (
{files.map((file, index) => (
{file.name} - {(file.size / 1024).toFixed(2)} KB
))}
);
};
Bu bileşen, seçilen dosyaların isimlerini ve boyutlarını ekrana yazdırır. Bellek sızıntılarını önlemek için useEffect içerisinde URL.revokeObjectURL metodunu çağırmayı unutmamalısınız.
Dosyaların Sunucuya Gönderilmesi
Dosyaları sunucuya göndermek için FormData nesnesini kullanmalıyız. FormData, dosya verilerini HTTP isteğinin gövdesine (body) doğru bir şekilde paketler. Fetch API kullanarak dosyaları bir API endpoint'ine nasıl göndereceğinizi aşağıda görebilirsiniz.
const uploadFiles = async (files) => {
const formData = new FormData();
files.forEach((file) => {
formData.append('files', file);
});
const response = await fetch('/api/upload', {
method: 'POST',
body: formData,
});
return response.json();
};
Bu örnekte, dosyaları döngüye alarak aynı anahtar (key) ismiyle FormData içerisine ekliyoruz. Sunucu tarafında bu dosyaları "files" anahtarı üzerinden yakalayabilirsiniz.
Yükleme Durumu ve İlerleme Takibi
Büyük dosyalar yüklenirken kullanıcıya bir ilerleme çubuğu (progress bar) göstermek, kullanıcı deneyimini önemli ölçüde artırır. Axios kütüphanesi, onUploadProgress özelliği ile bu süreci kolaylaştırır.
import axios from 'axios';
const uploadWithProgress = (files, setProgress) => {
const formData = new FormData();
files.forEach(file => formData.append('files', file));
axios.post('/api/upload', formData, {
onUploadProgress: (progressEvent) => {
const percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total);
setProgress(percentCompleted);
}
});
};
Bu kod bloğu, yükleme yüzdesini hesaplar ve bir state değişkenini güncelleyerek ilerleme çubuğunun dolmasını sağlar.
Karşılaştırma: Dosya Yükleme Yöntemleri
| Yöntem | Avantajı | Dezavantajı |
|---|---|---|
| Fetch API | Ekstra bağımlılık yok | İlerleme takibi manueldir |
| Axios | Dahili ilerleme takibi | Ek kütüphane gerektirir |
| Base64 Dönüşümü | Basit JSON yapısı | Dosya boyutunu %33 artırır |
Güvenlik Uyarısı: Sunucu tarafında dosya yüklemelerini kabul ederken her zaman dosya türü (MIME type) ve dosya boyutu kontrolü yapın. Yalnızca güvenilir dosya uzantılarına izin verin ve sunucu tarafında dosya adlarını yeniden oluşturarak "Path Traversal" saldırılarını engelleyin.
Sıkça Sorulan Sorular
React'te dosya yükleme boyutu nasıl sınırlandırılır?
Dosyaları state'e eklemeden önce file.size özelliğini kontrol ederek belirli bir bayt değerinin üzerindeki dosyaları reddedebilirsiniz.
Çoklu dosya yüklemede aynı dosyayı iki kez seçersem ne olur?
Varsayılan olarak input, aynı dosyayı tekrar seçmenize izin verir. Bunu engellemek için dosyaları state'e eklerken bir "Set" yapısı kullanarak benzersiz dosyaları tutabilirsiniz.
Sunucu tarafında hangi kütüphaneyi kullanmalıyım?
Node.js kullanıyorsanız Multer kütüphanesi, dosya yükleme işlemlerini yönetmek için endüstri standardıdır ve güvenlik için oldukça güçlüdür.
Yükleme sırasında hata oluşursa nasıl yönetirim?
try-catch blokları kullanarak ağ hatalarını yakalamalı ve kullanıcıya anlamlı bir hata mesajı dönmelisiniz.
Dosya önizlemesi neden yavaş çalışıyor?
Çok sayıda yüksek çözünürlüklü görseli aynı anda önizlemeye çalışmak tarayıcı belleğini tüketebilir. Küçük resimler (thumbnail) oluşturmak için canvas API'sini kullanabilirsiniz.
Sorumluluk Reddi: Bu makaledeki kod örnekleri eğitim amaçlıdır. Üretim ortamında (production) kullanmadan önce, sunucu tarafı güvenlik doğrulamalarını (dosya tarama, yetkilendirme) mutlaka uygulayın.
İleri Seviye İpuçları: Sürükle-Bırak (Drag-and-Drop) Entegrasyonu
Kullanıcı deneyimini iyileştirmek için standart dosya seçici butonunun yanı sıra, bir sürükle-bırak alanı eklemek oldukça etkilidir. React'te bu işlemi yönetmek için onDragOver, onDragLeave ve onDrop olaylarını kullanırız.
Aşağıdaki örnekte, bir div elementini nasıl bırakma alanı olarak yapılandıracağınızı görebilirsiniz:
const DropZone = ({ onFilesAdded }) => {
const handleDrop = (e) => {
e.preventDefault();
const files = Array.from(e.dataTransfer.files);
onFilesAdded(files);
};
return (
e.preventDefault()}
onDrop={handleDrop}
style={{ border: '2px dashed #ccc', padding: '20px', textAlign: 'center' }}
>
Dosyaları buraya sürükleyip bırakın
);
};
Performans Optimizasyonu: Büyük Dosyalar İçin Chunking (Parçalara Ayırma)
Çok büyük dosyaları tek bir HTTP isteği ile göndermek, ağ kopmaları veya sunucu zaman aşımı (timeout) hatalarına yol açabilir. Bu sorunu aşmak için dosyayı küçük parçalara (chunk) bölerek göndermek en güvenli yöntemdir.
Blob API ile Dosya Parçalama
JavaScript'in Blob.slice() metodunu kullanarak dosyayı belirli boyutlarda parçalara ayırabilir ve her parçayı sırayla sunucuya yükleyebilirsiniz.
const uploadInChunks = async (file) => {
const CHUNK_SIZE = 1024 * 1024; // 1MB
const totalChunks = Math.ceil(file.size / CHUNK_SIZE);
for (let i = 0; i < totalChunks; i++) {
const start = i * CHUNK_SIZE;
const end = Math.min(start + CHUNK_SIZE, file.size);
const chunk = file.slice(start, end);
const formData = new FormData();
formData.append('file', chunk);
formData.append('chunkIndex', i);
formData.append('fileName', file.name);
await fetch('/api/upload-chunk', {
method: 'POST',
body: formData
});
}
};
Güvenlik ve Validasyon Stratejileri
İstemci tarafındaki kontroller (dosya tipi, boyut sınırı) kullanıcıya hızlı geri bildirim vermek için gereklidir ancak asla tek başına yeterli değildir. Üretim ortamında aşağıdaki güvenlik katmanlarını mutlaka uygulamalısınız:
- MIME Type Kontrolü: Sadece uzantıya değil, dosyanın gerçek içeriğine (Magic Numbers) bakın.
- Dosya İsmi Sanitizasyonu: Kullanıcı tarafından gönderilen dosya isimlerini sunucuda yeniden adlandırarak "Directory Traversal" saldırılarını önleyin.
- Antivirüs Taraması: Yüklenen dosyaları sunucuda bir antivirüs motoru (örneğin ClamAV) ile taratın.
- Depolama Güvenliği: Yüklenen dosyaları web kök dizininin (web root) dışında bir alanda saklayın.
Örnek Güvenlik Tablosu
| Kontrol Noktası | Yöntem | Önemi |
|---|---|---|
| Dosya Uzantısı | Whitelist (izin verilenler listesi) | Yüksek |
| Dosya Boyutu | Sunucu taraflı limit | Orta |
| İçerik Analizi | Dosya imza kontrolü | Çok Yüksek |
Sonuç
React ile dinamik bir çoklu dosya yükleme bileşeni oluşturmak, doğru state yönetimi ve doğru API kullanımı ile oldukça verimli bir süreçtir. Bu rehberde, dosyaları seçmekten sunucuya göndermeye ve ilerleme takibi yapmaya kadar tüm adımları ele aldık. Bir sonraki adım olarak, sürükle-bırak (drag-and-drop) özelliğini ekleyerek kullanıcı deneyimini daha da ileriye taşıyabilirsiniz. Başarılar dilerim.


Yorumlar (0)
Yorum Yaz