Neden React?
Wed, Apr 8, 2015Hızlı cevap: uygulama state
‘ini yönetebilmek için.
Neyimiz Eksik ?
Modern web ugulamaları için uygulama state’lerini yönetmek ve uygulamanın bunlara cevap vermesini sağlamak gittikçe daha da zor bir hale geliyor.
Bugüne kadar bu sorunu büyük ölçüde istemci taraflı MVC (ya da benzer MVVM, MV-whatever) yapıları ile çözmeye çalıştık. (Knockout, Angular, Backbone …)
Geldiğimiz nokta şu:
Bir yerden sonra kim neyi güncelliyor ipin ucunu kaçırmak işten bile değil. Çünkü; uygulama state’lerinden her birinin değişip değişmediğini ve değiştiğinde uygulamanın ne yapması gerektiğini tek tek bizim söylememiz gerekiyor. Ayrıca uygulama state’lerinin birbirlerini güncellemesi ve kısır döngüler oluşturması da mümkün.
Bu güne kadarki uygulamamız nasıldı? State’deki değişimleri tespit etmeye çalışıp sadece o state’in etkilediği UI bölgelerini güncellemeye çalışmak. Böyle yaptık çünkü DOM manüplasyonu maliyetli bir işti ve mümkün olduğunca az güncelleme yapmamız gerekiyordu.
Durum böyle olunca, karmaşık state barındıran uygulamalarda UI’ı ve state’i senkronize tutabilmek başlı başına bir problem haline geldi.
Teorik olarak en büyük sorun buydu, state değişimlerine ayak uydurmak. Ancak bunu çözerken izlediğimiz yollar da bize performans kayıpları getiriyordu. Observable yapılar ile sadece değişen state’in etkilediği UI bölgelerini otomatik olarak güncellemek başta mantıklı gelse de ölçeklenebilir bir yaklaşım olmadığı ortadaydı (Knockout). Örneğin sayfada yirmi tane Observable bölge varsa bunları tek tek güncellemek ciddi performans kaybı demektir. Angular’ın dirty checking yaklaşımı göreceli olarak performanslı olsa da gerekli gereksiz her yerde state değişikliklerini yine de biz izlemek durumundaydık.
React Ne Vaadediyor?
Sorunumuz bu. State değişikliklerini tespit etmekte ve UI’ı bu state’i temsil edecek şekilde senkron etmekte zorlanıyoruz. React diyor ki, state değişikliklerini tespit etme! Uygulama state’inde en ufak bir değişimde tüm UI’ı tekrar oluştur. Neyin değişip neyin değişmediğiyle ilgilenme.
Ne kadar performanslı değil mi? Biz daha önce sadece kısmi güncellemeler yaparken performans sorunları yaşarken, şimdi uygulama state’i içerisinde en ufak bir değişimde tüm UI’ı tekrar oluşturacağız.
Bu yaklaşım aslında tanıdık. Sunucu taraflı UI rendering’i tam da böyle yapıyoruz. Bu açıdan state değişimleri uygulamada karmaşaya yol açmıyor. Peki bu yaklaşımı client tarafında uygulamayı daha önce niye hiç düşünmedik? Çünkü DOM manipülasyonu zaten çok maliyetli iken tüm UI’ı tekrar oluşturmak mantıklı değildi, tabi eğer UI rendering işlemini direk olarak DOM üzerine yapıyorsanız!
Pür fonksiyon şeklinde UI
React’in getirdiği aslında en radikal yaklaşım burada. React, her seferinde tüm UI baştan render ediyor evet, ama direk olarak DOM üzerine değil. Browser hafızasında yaşayan sanal bir DOM üzerine tüm UI’ı render ediyor. Daha sonra bu sanal DOM, state değişmeden bir önceki sanal DOM ile karşılaştırılıyor. Aradaki farkı yaratacak minimum gerçek DOM manipülasyonları hesaplanıyor. Daha sonra React gerçek browser DOM’unu bu minimum operasyonlar ile enaz maliyetle bir kerede güncelliyor. Muazzam bir soyutlama katmanı (Layer of abstraction, http://en.wikipedia.org/wiki/Abstraction_layer)
Web uygulaması geliştiren programcı olarak biz, state değişimlerinin tespiti ve bu değişimlere nasıl tepki verilmesi gerektiği gibi konularda kafa yormamış oluyoruz, sadece tüm uygulamayı yeni state’i temsile edecek şekilde baştan render ediyoruz.
Bu sayede tüm UI bir pür fonksiyon (pure function, http://en.wikipedia.org/wiki/Pure_function) şeklini alıyor. Yani verilen bir stete için her zaman aynı çıktıyı üretiyor.
Bu yaklaşım tabi ki ideal olanı. Uygulama bileşenlerini birer pür fonksiyon şeklinde yapılandırmak programcıya düşüyor, React’ın bir zorlayıcılığı yok. Gerçek hayat şartlarında tüm uygulama bileşenlerini pür olarak yapılandırmak da gerçekçi değil, özellikle kullanıcı müdahalesi olan kısımlarda.
Şunu da belirtmem gerekir ki, burada bahsettiğm yaklaşım “ideal” React uygulamaları için geçerli. Mevcut mvc yapısı olan bir uygulamaya React’i entegre etmek de mümkün. Örneğin yüksek DOM performansı gerektiren view bölgelerinde Angular’in view katmanı olarak React’in kullanıldığı görülmekte.
Performans
İlk olarak DOM güncellemede React’in nasıl bir performans artışı getirdiğini gördük. Buna ek olarak, React’in tüm UI’ı tekrar render etme yaklaşımı beraberinde ölçeklenebiliriği de getiriyor. Yani on güncelleme yapmak ile yirmi güncelleme yapmak arasında üstel bir maliyet farkı bulunmuyor, doğrusal bir rendering süresi artışı sözkonusu.
Sadece iki görev üstlenen React’in ikinci görevi ise browser event’lerine cevap vermektir. Bu noktada da güzel bir yaklaşım sergilemişler ve sentetik event’ler oluşturmuşlar. React nesneleri üzerinde oluşan event’ler aslında gerçek browser event’leri değil. React sayfa çapında tek bir event delegasyonu ile tüm olan olayları yakalayıp ilgili nesnelere bu olayları uyarı olarak gönderiyor.
DOM manipülasyonundan sonra web uygulaması performansını düşüren bir diğer unsur event listener’lardır. Ne kadar fazla DOM node’u event-listener’e sahipse browser üzerinde o kadar yük oluşur. React’in yaklaşımı sayesinde tüm uygulama sadece bir tane event-listener ile idare edilmiş oluyor. Ve yine buna ek olarak, oluşan event’leri React sentetik olarak üretip dispatch ettiği için cross-browser bir hale getirerek bunu yapabiliyor. Uygulamayı hangi browser üzerinde çalıştırdığınızdan bağımsız olarak bir event oluştuğunda elinize düşen event nesnesi standardize edilmiş bir yapıda oluyor.
Izomorfizm
Tüm UI’ı sanal bir biçimde ifade ettiğimize göre, bu soyut ağaç yapısını istersek browser DOM node’larına dönüştürüp istemci tarafında UI’ı render edebiliriz ya da başka bir şekilde kullanabiliriz. Mesela sunucu tarafında html string’i oluşturup, aynı UI’ı sunucu tarafında oluşturabilir, istemciye önceden render edilmiş bir sayfa gösterebiliriz.
Bunu yaklaşımı instagram şuan uyguluyor. Sayfada herhangi bir resme tıkladığınızda bu resim daha büyük olacak şekilde istemci tarafında render edilen bir UI üzerinde gösteriliyor. Bu state değişikliği URL’e de yansıyor. Bu URL’i alıp browser penceresine yapıştırdığınızda ise bu state sunucuda render edilmiş haliyle karşınıza geliyor. Sunucuda ve istemcide çalışabilen bir rendering yaklaşımı!
Sonuç
Getirdiği yaklaşım ile React, bence web uygulamalarının geleceğidir. Sanal DOM ağacı ile oluşturulan soyutlama katmanı sayesinde uygulama bileşenlerini browser DOM’una render edilebilmekte, sunucuda html çıktısı üretebilmekte ve hatta native mobil uygulama arayüzleri oluşturulabilmekte. IOS için React Native henüz yeni yayınlandı (http://facebook.github.io/react-native/). Sanıyorum yakında çok daha farklı kullanım alanları da görebileceğiz.