React Context Selector Deseni ile yeniden oluşturmaları optimize edip performansı nasıl artıracağınızı öğrenin. Pratik örnekler ve en iyi uygulamalar içerir.
React Context Selector Deseni: Performans İçin Yeniden Oluşturmaları Optimize Etme
React Context API, uygulamalarınızdaki küresel durumu yönetmek için güçlü bir yol sunar. Ancak, Context kullanırken yaygın bir zorluk ortaya çıkar: gereksiz yeniden oluşturmalar (re-render). Context değeri değiştiğinde, o Context'i tüketen tüm bileşenler, Context verilerinin yalnızca küçük bir kısmına bağımlı olsalar bile yeniden oluşturulur. Bu, özellikle daha büyük ve daha karmaşık uygulamalarda performans darboğazlarına yol açabilir. Context Selector Deseni, bileşenlerin yalnızca ihtiyaç duydukları Context'in belirli kısımlarına abone olmalarını sağlayarak gereksiz yeniden oluşturmaları önemli ölçüde azaltan bir çözüm sunar.
Sorunu Anlamak: Gereksiz Yeniden Oluşturmalar
Bunu bir örnekle gösterelim. Kullanıcı bilgilerini (isim, e-posta, ülke, dil tercihi, sepet öğeleri) bir Context sağlayıcısında saklayan bir e-ticaret uygulaması hayal edin. Kullanıcı dil tercihini güncellerse, yalnızca kullanıcının adını görüntüleyenler de dahil olmak üzere Context'i tüketen tüm bileşenler yeniden oluşturulur. Bu verimsizdir ve kullanıcı deneyimini etkileyebilir. Farklı coğrafi konumlardaki kullanıcıları düşünün; Amerikalı bir kullanıcı profilini güncellerse, Avrupalı bir kullanıcının ayrıntılarını gösteren bir bileşen yeniden oluşturulmamalıdır.
Yeniden Oluşturmalar Neden Önemlidir
- Performans Etkisi: Gereksiz yeniden oluşturmalar değerli CPU döngülerini tüketir, bu da daha yavaş görüntülemeye ve daha az duyarlı bir kullanıcı arayüzüne yol açar. Bu, özellikle düşük güçlü cihazlarda ve karmaşık bileşen ağaçlarına sahip uygulamalarda fark edilir.
- Kaynak İsrafı: Değişmeyen bileşenleri yeniden oluşturmak, özellikle veri alırken veya pahalı hesaplamalar yaparken bellek ve ağ bant genişliği gibi kaynakları israf eder.
- Kullanıcı Deneyimi: Yavaş ve duyarsız bir kullanıcı arayüzü kullanıcıları hayal kırıklığına uğratabilir ve kötü bir kullanıcı deneyimine yol açabilir.
Context Selector Deseni ile Tanışın
Context Selector Deseni, bileşenlerin yalnızca ihtiyaç duydukları Context'in belirli kısımlarına abone olmalarını sağlayarak gereksiz yeniden oluşturma sorununu ele alır. Bu, Context değerinden gerekli verileri çıkaran bir seçici (selector) işlevi kullanılarak elde edilir. Context değeri değiştiğinde, React seçici işlevinin sonuçlarını karşılaştırır. Seçilen veri değişmediyse (katı eşitlik, ===
kullanarak), bileşen yeniden oluşturulmaz.
Nasıl Çalışır
- Context'i Tanımlayın:
React.createContext()
kullanarak bir React Context'i oluşturun. - Bir Sağlayıcı (Provider) Oluşturun: Context değerini alt bileşenlerine sunmak için uygulamanızı veya ilgili bölümü bir Context Sağlayıcısı ile sarmalayın.
- Seçicileri (Selectors) Uygulayın: Context değerinden belirli verileri çıkaran seçici işlevleri tanımlayın. Bu işlevler saf (pure) olmalı ve yalnızca gerekli verileri döndürmelidir.
- Seçiciyi Kullanın: Seçilen veriyi almak ve yalnızca o verideki değişikliklere abone olmak için
useContext
ve seçici işlevinizden yararlanan özel bir hook (veya bir kütüphane) kullanın.
Context Selector Desenini Uygulama
Birçok kütüphane ve özel uygulama, Context Selector Deseni'ni kolaylaştırabilir. Özel bir hook kullanarak yaygın bir yaklaşımı inceleyelim.
Örnek: Basit bir Kullanıcı Context'i
Aşağıdaki yapıya sahip bir kullanıcı context'i düşünün:
const UserContext = React.createContext({
name: 'John Doe',
email: 'john.doe@example.com',
country: 'USA',
language: 'en',
theme: 'light'
});
1. Context'i Oluşturma
const UserContext = React.createContext({
name: 'John Doe',
email: 'john.doe@example.com',
country: 'USA',
language: 'en',
theme: 'light'
});
2. Sağlayıcıyı (Provider) Oluşturma
const UserProvider = ({ children }) => {
const [user, setUser] = React.useState({
name: 'John Doe',
email: 'john.doe@example.com',
country: 'USA',
language: 'en',
theme: 'light'
});
const updateUser = (updates) => {
setUser(prevUser => ({ ...prevUser, ...updates }));
};
const value = React.useMemo(() => ({ user, updateUser }), [user]);
return (
{children}
);
};
3. Seçici (Selector) ile Özel bir Hook Oluşturma
import React from 'react';
function useUserContext() {
const context = React.useContext(UserContext);
if (!context) {
throw new Error('useUserContext must be used within a UserProvider');
}
return context;
}
function useUserSelector(selector) {
const context = useUserContext();
const [selected, setSelected] = React.useState(() => selector(context.user));
React.useEffect(() => {
setSelected(selector(context.user)); // Initial selection
const unsubscribe = context.updateUser;
return () => {}; // No actual unsubscription needed in this simple example, see below for memoizing.
}, [context.user, selector]);
return selected;
}
Önemli Not: Yukarıdaki `useEffect` uygun memoizasyondan yoksundur. `context.user` değiştiğinde, seçilen değer aynı olsa bile *her zaman* yeniden çalışır. Sağlam, memoize edilmiş bir seçici için sonraki bölüme veya `use-context-selector` gibi kütüphanelere bakın.
4. Seçici Hook'unu bir Bileşende Kullanma
function UserName() {
const name = useUserSelector(user => user.name);
return Name: {name}
;
}
function UserEmail() {
const email = useUserSelector(user => user.email);
return Email: {email}
;
}
function UserCountry() {
const country = useUserSelector(user => user.country);
return Country: {country}
;
}
Bu örnekte, UserName
, UserEmail
ve UserCountry
bileşenleri yalnızca seçtikleri belirli veriler (sırasıyla isim, e-posta, ülke) değiştiğinde yeniden oluşturulur. Kullanıcının dil tercihi güncellenirse, bu bileşenler yeniden oluşturulmaz, bu da önemli performans iyileştirmeleri sağlar.
Seçicileri ve Değerleri Memoize Etme: Optimizasyon İçin Gerekli
Context Selector deseninin gerçekten etkili olabilmesi için memoizasyon çok önemlidir. Bu olmadan, seçici işlevler altta yatan veri anlamsal olarak değişmemiş olsa bile yeni nesneler veya diziler döndürebilir, bu da gereksiz yeniden oluşturmalara yol açar. Benzer şekilde, sağlayıcı değerinin de memoize edildiğinden emin olmak önemlidir.
Sağlayıcı Değerini useMemo
ile Memoize Etme
useMemo
kancası, UserContext.Provider
'a iletilen değeri memoize etmek için kullanılabilir. Bu, sağlayıcı değerinin yalnızca altta yatan bağımlılıklar değiştiğinde değişmesini sağlar.
const UserProvider = ({ children }) => {
const [user, setUser] = React.useState({
name: 'John Doe',
email: 'john.doe@example.com',
country: 'USA',
language: 'en',
theme: 'light'
});
const updateUser = (updates) => {
setUser(prevUser => ({ ...prevUser, ...updates }));
};
// Memoize the value passed to the provider
const value = React.useMemo(() => ({
user,
updateUser
}), [user, updateUser]);
return (
{children}
);
};
Seçicileri useCallback
ile Memoize Etme
Seçici işlevleri bir bileşen içinde satır içi olarak tanımlanırsa, mantıksal olarak aynı olsalar bile her oluşturmada yeniden oluşturulurlar. Bu, Context Selector deseninin amacını boşa çıkarabilir. Bunu önlemek için, seçici işlevlerini memoize etmek üzere useCallback
kancasını kullanın.
function UserName() {
// Memoize the selector function
const nameSelector = React.useCallback(user => user.name, []);
const name = useUserSelector(nameSelector);
return Name: {name}
;
}
Derin Karşılaştırma ve Değişmez Veri Yapıları
Context içindeki verilerin derinlemesine iç içe olduğu veya değiştirilebilir nesneler içerdiği daha karmaşık senaryolar için, değişmez veri yapıları (örneğin, Immutable.js, Immer) kullanmayı veya seçicinizde bir derin karşılaştırma işlevi uygulamayı düşünün. Bu, altta yatan nesneler yerinde değiştirilmiş olsa bile değişikliklerin doğru bir şekilde algılanmasını sağlar.
Context Selector Deseni için Kütüphaneler
Birçok kütüphane, Context Selector Deseni'ni uygulamak için hazır çözümler sunar, süreci basitleştirir ve ek özellikler sunar.
use-context-selector
use-context-selector
, bu amaç için özel olarak tasarlanmış popüler ve iyi bakımlı bir kütüphanedir. Bir Context'ten belirli değerleri seçmek ve gereksiz yeniden oluşturmaları önlemek için basit ve etkili bir yol sunar.
Kurulum:
npm install use-context-selector
Kullanım:
import { useContextSelector } from 'use-context-selector';
function UserName() {
const name = useContextSelector(UserContext, user => user.name);
return Name: {name}
;
}
Valtio
Valtio, verimli durum güncellemeleri ve seçici yeniden oluşturmalar için proxy'leri kullanan daha kapsamlı bir durum yönetimi kütüphanesidir. Durum yönetimine farklı bir yaklaşım sunar ancak Context Selector Deseni ile benzer performans avantajları elde etmek için kullanılabilir.
Context Selector Deseninin Faydaları
- Geliştirilmiş Performans: Gereksiz yeniden oluşturmaları azaltarak daha duyarlı ve verimli bir uygulamaya yol açar.
- Azaltılmış Bellek Tüketimi: Bileşenlerin gereksiz verilere abone olmasını önleyerek bellek ayak izini azaltır.
- Artan Sürdürülebilirlik: Her bileşenin veri bağımlılıklarını açıkça tanımlayarak kod netliğini ve sürdürülebilirliğini artırır.
- Daha İyi Ölçeklenebilirlik: Bileşen sayısı ve durumun karmaşıklığı arttıkça uygulamanızı ölçeklendirmeyi kolaylaştırır.
Context Selector Deseni Ne Zaman Kullanılır
Context Selector Deseni özellikle aşağıdaki senaryolarda faydalıdır:
- Büyük Context Değerleri: Context'iniz büyük miktarda veri depoladığında ve bileşenlerin bunun yalnızca küçük bir alt kümesine ihtiyacı olduğunda.
- Sık Context Güncellemeleri: Context değeri sık sık güncellendiğinde ve yeniden oluşturmaları en aza indirmek istediğinizde.
- Performans açısından Kritik Bileşenler: Belirli bileşenler performans açısından hassas olduğunda ve yalnızca gerektiğinde yeniden oluşturulmalarını sağlamak istediğinizde.
- Karmaşık Bileşen Ağaçları: Derin bileşen ağaçlarına sahip uygulamalarda, gereksiz yeniden oluşturmaların ağaç boyunca yayılabileceği ve performansı önemli ölçüde etkileyebileceği durumlarda. Karmaşık bir tasarım sistemi üzerinde çalışan küresel olarak dağıtılmış bir ekip düşünün; bir konumdaki bir düğme bileşenindeki değişiklikler tüm sistemde yeniden oluşturmaları tetikleyebilir ve diğer saat dilimlerindeki geliştiricileri etkileyebilir.
Context Selector Desenine Alternatifler
Context Selector Deseni güçlü bir araç olsa da, React'te yeniden oluşturmaları optimize etmek için tek çözüm değildir. İşte birkaç alternatif yaklaşım:
- Redux: Redux, tek bir depo (store) ve öngörülebilir durum güncellemeleri kullanan popüler bir durum yönetimi kütüphanesidir. Durum güncellemeleri üzerinde hassas kontrol sunar ve gereksiz yeniden oluşturmaları önlemek için kullanılabilir.
- MobX: MobX, gözlemlenebilir (observable) verileri ve otomatik bağımlılık takibini kullanan başka bir durum yönetimi kütüphanesidir. Bileşenleri yalnızca bağımlılıkları değiştiğinde otomatik olarak yeniden oluşturur.
- Zustand: Basitleştirilmiş flux ilkelerini kullanan küçük, hızlı ve ölçeklenebilir, temel bir durum yönetimi çözümüdür.
- Recoil: Recoil, Facebook'tan gelen, durum güncellemeleri üzerinde hassas kontrol sağlamak ve gereksiz yeniden oluşturmaları önlemek için atomları ve seçicileri kullanan deneysel bir durum yönetimi kütüphanesidir.
- Bileşen Kompozisyonu: Bazı durumlarda, verileri bileşen propları aracılığıyla aşağı doğru geçirerek küresel durum kullanmaktan tamamen kaçınabilirsiniz. Bu, performansı artırabilir ve uygulamanızın mimarisini basitleştirebilir.
Küresel Uygulamalar için Dikkat Edilmesi Gerekenler
Küresel bir kitle için uygulamalar geliştirirken, Context Selector Deseni'ni uygularken aşağıdaki faktörleri göz önünde bulundurun:
- Uluslararasılaştırma (i18n): Uygulamanız birden çok dili destekliyorsa, Context'inizin kullanıcının dil tercihini sakladığından ve dil değiştiğinde bileşenlerinizin yeniden oluşturulduğundan emin olun. Ancak, diğer bileşenlerin gereksiz yere yeniden oluşturulmasını önlemek için Context Selector desenini uygulayın. Örneğin, bir para birimi dönüştürücü bileşeninin yalnızca kullanıcının konumu değiştiğinde, varsayılan para birimini etkileyerek yeniden oluşturulması gerekebilir.
- Yerelleştirme (l10n): Veri biçimlendirmesindeki kültürel farklılıkları (örneğin, tarih ve saat biçimleri, sayı biçimleri) göz önünde bulundurun. Yerelleştirme ayarlarını saklamak için Context'i kullanın ve bileşenlerinizin verileri kullanıcının yerel ayarına göre oluşturduğundan emin olun. Yine, seçici desenini uygulayın.
- Zaman Dilimleri: Uygulamanız zamana duyarlı bilgiler gösteriyorsa, zaman dilimlerini doğru şekilde ele alın. Kullanıcının saat dilimini saklamak için Context'i kullanın ve bileşenlerinizin zamanları kullanıcının yerel saatinde gösterdiğinden emin olun.
- Erişilebilirlik (a11y): Uygulamanızın engelli kullanıcılar için erişilebilir olduğundan emin olun. Erişilebilirlik tercihlerini (örneğin, yazı tipi boyutu, renk kontrastı) saklamak için Context'i kullanın ve bileşenlerinizin bu tercihlere uyduğundan emin olun.
Sonuç
React Context Selector Deseni, React uygulamalarında yeniden oluşturmaları optimize etmek ve performansı artırmak için değerli bir tekniktir. Bileşenlerin yalnızca ihtiyaç duydukları Context'in belirli kısımlarına abone olmalarını sağlayarak, gereksiz yeniden oluşturmaları önemli ölçüde azaltabilir ve daha duyarlı ve verimli bir kullanıcı arayüzü oluşturabilirsiniz. Maksimum optimizasyon için seçicilerinizi ve sağlayıcı değerlerinizi memoize etmeyi unutmayın. Uygulamayı basitleştirmek için use-context-selector
gibi kütüphaneleri göz önünde bulundurun. Giderek daha karmaşık uygulamalar oluşturdukça, Context Selector Deseni gibi teknikleri anlamak ve kullanmak, performansı korumak ve özellikle küresel bir kitle için harika bir kullanıcı deneyimi sunmak için çok önemli olacaktır.