React uygulamalarında modallar genellikle basit bir boolean değeriyle kontrol edilir: aç/kapat durumu, kapatma callback'leri ve şartlı renderlar. Bu yaklaşım küçük projelerde işe yarasa da, gerçek dünya uygulamalarında modallar genellikle karmaşık iş akışlarının parçası haline gelir. Örneğin bir raporun adını değiştirmek, tarih aralığı seçmek veya yıkıcı bir işlemi onaylamak gibi durumlar modalların sadece bir UI ögesi olmaktan çıkıp uygulama mantığıyla doğrudan bağlantılı hale gelmesini gerektirir.
Bu gereksinimlerin karşılanması için modalların, tip güvenliği olan async operasyonlar olarak tasarlanması gerekiyor. Bu yaklaşım, hem geliştirme sürecini kolaylaştırıyor hem de çalışma zamanında oluşabilecek hataları minimize ediyor.
Geleneksel Modal Yönetiminin Sınırları
Çoğu React uygulamasında modallar yerel state'lerle yönetilir. Bir sayfa bileşeni içinde isModalOpen gibi bir boolean değeri ve buna bağlı olarak şartlı renderlar kullanılır. Ancak uygulamalar büyüdükçe bu yaklaşımın getirdiği sorunlar ortaya çıkar:
- Farklı modal türleri için ayrı state'ler yönetmek (örneğin
isRenameOpen,isDeleteOpen,isShareOpen) kodun karmaşıklığını artırır - Modallar arası veri akışını sağlamak için callback zincirleri oluşturmak gerekir
- Modal state'lerinin nerede yönetileceği konusunda belirsizlikler ortaya çıkar
- Test senaryolarında state'lerin birbirine karışma riski oluşur
Bu durum, uygulama mantığının modal UI'sından ayrılmasını zorlaştırır ve kodun bakımını giderek karmaşıklaştırır.
Promise Tabanlı Modalların Avantajları
Bazı modal kütüphaneleri zaten promise tabanlı API'ler sunuyor. Örneğin @ebay/nice-modal-react popüler bir çözüm olsa da, sonuç tipi genellikle any olarak tanımlanıyor. Bu durum TypeScript'in tip güvenliğini ortadan kaldırıyor:
const result = await NiceModal.show("rename-report", data);
// result.nme; // Tip hatası yakalanmaz
// result.whatever; // Tip hatası yakalanmaz
// result.name; // Sadece runtime'da hata oluşabilirOysa tip güvenliği olan bir modal sistemi, hem girdi hem de çıktı tiplerini otomatik olarak çıkarabilir. Örneğin bir rapor adını değiştirmek için kullanılan modal:
const result = await modal.open(renameReportModal, {
reportId: report.id,
currentName: report.name,
});
if (result.status === "renamed") {
await renameReport({
id: report.id,
name: result.name,
});
}Bu yaklaşımda TypeScript, modalın gerektirdiği girdileri, close() fonksiyonuna geçilebilecek tipleri ve sonuç tipini otomatik olarak çıkarır. Eğer RenameReportResult tipinde bir değişiklik yapılırsa, tüm kullanım noktaları derleme aşamasında hata verecektir — runtime hatalarından çok daha güvenli bir yaklaşım.
Tip Güvenliği Olan Modal Yönetimi Nasıl Kurulur?
Yeni nesil modal yönetim sistemleri, tip güvenliğini merkeze alan birkaç temel ilkeye dayanıyor:
- Modal girdileri ve sonuçları TypeScript tarafından otomatik olarak çıkarılmalı
- Modal state'leri global değil, scoped olarak yönetilmeli
- UI katmanı kolayca değiştirilebilir olmalı
- Modallar hem React bileşenleri içinden hem de dışından açılabilir olmalı
- Kapama, reddetme ve açıkta bırakma işlemleri açık yaşam döngüsü sonuçları olarak tanımlanmalı
Bu ilkeler doğrultusunda kurulan bir sistemde, uygulama mantığı modal UI'sından tamamen ayrılır. Geliştiriciler sadece async/await kullanarak modal akışlarını yönetebilirler.
Örnek Uygulama: Rapor Adını Değiştirme
Tip güvenliği olan bir modal sistemi kurmak için öncelikle modal provider'ı uygulamaya eklemek gerekiyor:
import { ModalProvider, useModalManager } from "@okyrychenko-dev/react-modal-manager";
function App() {
return (
<ModalProvider>
<ReportsPage />
</ModalProvider>
);
}Ardından modalı tanımlamak için özel bir modal bileşeni oluşturulur. Bu bileşen, hem girdi hem de çıktı tiplerini açıkça tanımlar:
import { createModal, type ModalComponentProps } from "@okyrychenko-dev/react-modal-manager";
interface RenameReportInput {
reportId: string;
currentName: string;
}
type RenameReportResult =
| { status: "renamed"; name: string }
| { status: "cancelled" };
function RenameReportModal({
input,
close,
}: ModalComponentProps<RenameReportInput, RenameReportResult>) {
const [name, setName] = useState(input.currentName);
return (
<dialog open>
<h2>Rapor Adını Değiştir</h2>
<input
value={name}
onChange={(e) => setName(e.target.value)}
/>
<button onClick={() => close({ status: "cancelled" })}
>İptal
</button>
<button onClick={() => close({ status: "renamed", name })}
>Değiştir
</button>
</dialog>
);
}
export const renameReportModal = createModal<RenameReportInput, RenameReportResult>({
component: RenameReportModal,
});Bu tanımlamayla birlikte, modalı çağıran her yerde tam tip güvenliği elde edilir. Örneğin bir düğmeye tıklanıldığında:
async function handleRename() {
const result = await modal.open(renameReportModal, {
reportId: report.id,
currentName: report.name,
});
if (result.status === "renamed") {
await renameReport({
id: report.id,
name: result.name,
});
}
}TypeScript otomatik olarak modalın gerektirdiği girdileri ve mümkün sonuç tiplerini çıkarır. Eğer result.name yerine hatalı bir result.nme yazılırsa, derleme aşamasında hata alınır.
Geleceğe Yönelik Yaklaşımlar
Tip güvenliği olan modal yönetimi, React uygulamalarında modalların sadece UI ögeleri olmaktan çıkıp uygulama mantığıyla bütünleşmelerini sağlıyor. Bu yaklaşımın getirdiği avantajlar arasında:
- Daha az hata eğilimli kod
- Daha kolay bakım ve ölçeklenebilirlik
- Uygulama mantığı ve UI katmanlarının net bir şekilde ayrılması
- Geliştirici deneyiminin iyileştirilmesi
Geliştiriciler, artık modalların async operasyonlar olduğunu ve tip güvenliğinin önemli olduğunu kabul ediyorlar. Bu yeni nesil modal yönetim sistemleri, React uygulamalarında daha güvenilir ve ölçeklenebilir modallar oluşturmanın yolunu açıyor.
Uygulama karmaşıklaştıkça, tip güvenliğine sahip modal sistemleri projelerin uzun vadeli sağlığını koruma konusunda kritik bir rol oynayacak. Bu yaklaşımı benimseyen ekipler, hem geliştirme sürecini hızlandırıyor hem de üretim ortamında karşılaşabilecekleri beklenmedik sorunları minimize ediyorlar.
Yapay zeka özeti
React uygulamalarında modallar için tip güvenliğini nasıl sağlarsınız? Promise<TResult> tabanlı modal yönetimiyle async operasyonları basitleştirin ve hata riskini azaltın.