React.lazy ve React Suspense Nedir?
Web uygulamaları gün geçtikçe karmaşıklaşmaya ve büyümeye devam ediyor. Bu durum çoğu zaman performans sorunlarını da beraberinde getiriyor. Fakat biz geliştiriciler uygulama ne kadar büyürse büyüsün son kullanıcının ulaşabilirliğini en yüksek seviyede tutmak zorunda. Bu yüzden geliştirdiğimiz uygulama genelinde performans ile ilgili iyileştirmeler yapmalı ve kaynakları en verimli şekilde kullanmalıyız 😕.
Tüm UI işlemlerini javascript'in sırtına yüklediğimiz şu dönemlerde de bu durum fazlasıyla önem arz ediyor. Özellikle React, Vue, Angular gibi araçlar kullanıyorsak kodumuz build olduğunda dosya boyutu büyük bir bundle (kodumuzun tek bir javascript dosyası haline gelmesi 📦) çıktısı alırız. Bu bundle içinde kullanıcının uygulamada geçirdiği süre boyunca hiç etkileşime girmeyeceği kısımlarda bulunacaktır. Bu bundle içinde sadece kullanıcın etkileşime gireceği ve uygulamamızın çalışması için gereken kısımların olması performans açısından uygulamamıza büyük bir fayda sağlayacaktır 💡.
Bir React kodu üzerinde sorunu daha net anlamaya çalışalım.
import React from 'react'
// Components
import Header from './components/Header'
import LoginModal from './components/LoginModal'
import NotificationPopup from './components/NotificationBar'
import Product from './components/Product'
import ProductReviews from './components/Product/Reviews'
import SideMenu from './components/SideMenu'
const App = () => (
<>
<Header />
<SideMenu />
<NotificationPopup />
<Product />
<ProductReviews />
<LoginModal />
</>
)
export default App
Yukarıdaki React kodunu incelediğimiz bazı component'ların bundle dosyamızda bulunması çok da mantıklı değil. Örneğin <LoginModal />
component'ı kullanıcı giriş yapmak istemediği sürece kullanılmayacak. Aynı şekilde <ProductReviews />
component'ı kullanıcı ürün yorumları tab'ına tıklamadığı sürece devreye girmeyecek. Bu componentları bundle dosyamızdan bir şekilde kaldırmak ve kullanıcı etkileşime gireceği zaman yüklemek uygulamamızın performansını büyük ölçüde arttıracaktır.
Code Splitting
Kodumuzu ufak parçalara (chunk) bölüp ve bu parçaların uygulamanın çalışma zamanında isteğe göre yüklenmesini sağlamaya code splitting yani kod bölümleme diyoruz. Webpack
, Browserify
, Rollup
gibi araçlar ile bu konfigürasyonu yapmak mümkün. Daha kolayı da var. Eğer Create React App
, Gatsby
veya Next.js
gibi araçlar kullanıyorsanız bu özellik built-in olarak geliyor.
⚠️ Uygulamanızda Client Side Routing yapıyorsanız mutlaka code splitting yapmaya özen göstermelisiniz.
Sorunu anladığımıza ve kısaca code splitting'den bahsettiğimize göre artık React tarafında bunu hallediyoruz kısmına geçebiliriz.
React.lazy()
Component'larımızı dinamik olarak yüklemeyi sağlayan metod React.lazy()
'dir. Bu metod parametre olarak dinamik yüklediğimiz component'ı saran bir fonksiyon olmalıdır.
⚠️ React.lazy()'e verdiğimiz parametre promise dönmelidir.
// Geleneksel yöntem:
import LoginModal from './components/LoginModal'
// React.lazy() dinamik import yöntemi:
const LoginModal = React.lazy(() => import('./components/LoginModal'))
Ufak bir değişiklikle LoginModal
component'ını dinamik olarak yüklemiş olduk. Şimdi de bu component'ı render etme kısmına geçelim.
React Suspense
Dinamik olarak yüklediğimiz component'ı render edip ve bu component yüklenene kadar geçen zamanda yedek bir içerik gösterebilmemize yarayan React'ın özel component'ı Suspense
'dir. Suspense
component'ı fallback
adında tek bir props
alır. Ve bu fallback
props
'u dinamik component'ımız yüklenene kadar veya component yüklenmesinde herhangi bir sorun olduğu zaman render edilecek içeriği belirttiğimiz yerdir.
import React, { Suspense } from 'react'
// Dynamic Imports
const LoginModal = React.lazy(() => import('./components/LoginModal'))
const App = () => {
// ...
const showLoginModal = () => {}
return (
<>
{/* ... */}
<button onClick={showLoginModal}>Giriş Yap</button>
{isLoginModalOpen && (
<Suspense fallback={<div>Yükleniyor...</div>}>
<LoginModal />
</Suspense>
)}
{/* ... */}
</>
)
}
Basitçe Suspense
kullanımı bu şekilde. Ayrıca fallback
props
'u olarak bir component da verebiliyoruz.
<Suspense fallback={<LoadingOverlay />}>
<LoginModal />
</Suspense>
Bu yazıyı ufak bir örnek ve bu örneğin sonuçlarını göstererek bitirmek istiyorum. Public bir api'den kullanıcıları listeleyen küçük bir react uygulaması yapacağız. Kullanıcı kişileri göster butonuna tıkladığında api'ye istek atıp dönen isteğin cevabında dinamik olarak oluşturduğumuz UserList
component'ını render edeceğiz.
Yukarıdaki iframe'den bu yazı için geliştirdiğimiz minik uygulamayı görebilirsiniz. Son olarak yaptıklarımız işe yaradı mı gerçekten de code splitting yapabildik mi inceleyelim. Tarayıcımızdan developer tools'u açalım ve network tab'ına tıklayalım sayfayı yenileyelim.
Kullanıcıları göster butonuna basmadan önce:
Kullanıcıları göster butonuna bastıktan sonra:
Ekran görüntüleri de gösteriyor ki Suspense
ve React.lazy()
gayet güzel bir şekilde çalışıyor 🥳. UserList
component'ını isteğe bağlı olarak sadece etkileşime geçileceği zaman yüklemiş olduk.
Yorumlar
Soru, cevap ve destekleriniz için aşağıdan yorum bırakmayı unutmayın.