Merhaba👋🏻,
Bu makale, birden fazla bileşen arasındaki durumu yönetmek için daha etkili yöntemler öğrenmek isteyen yeni başlayanlar için özel olarak oluşturulmuştur. Ayrıca, kodunuzun bakımını ve anlaşılmasını zorlaştıran pervane sondajı sorununu da ele almayı amaçlamaktadır. Bağlam API'sinin ne tür bir sorunu çözdüğüyle başlayalım.
Video formatını tercih ediyorsanız işte YouTube kanalımda izleyebileceğiniz eğitim.👇🏻
Bazen verileri bir ana bileşenden alt bileşene aktarmanız gerektiğini ve sonunda sahne malzemelerini aradaki bir grup bileşenden geçirmek zorunda kaldığınızı biliyor musunuz? Buna pervane delme denir ve hızlı bir şekilde ortalığı karıştırabilir. Bunu açıklığa kavuşturmak için bir örnek üzerinden gidelim.
Diyagramda gösterildiği gibi, uygulamanızın kökünde bulunan App
bileşeninden bazı verileri getirdiğinizi hayal edin. Şimdi, derinlemesine yuvalanmış bir bileşenin, örneğin Grandchild
bileşeninin bu verilere erişmesi gerekiyorsa, genellikle bunu Grandchild
ulaşmadan önce destek olarak Parent
ve Child
bileşenlerinden geçirirsiniz. Uygulamanız büyüdükçe bu durum çirkinleşebilir.
İşte başka bir görsel temsil:
Yukarıdaki örnekte, Profile
bileşeni kullanıcı verilerine ihtiyaç duyar ancak bu ara bileşenler verileri kendileri kullanmasa bile bu verilerin öncelikle App
ve Navigation
bileşenleri üzerinden geçmesi gerekir. Peki bunu nasıl temizleyeceğiz? Bağlam API'sinin kullanışlı olduğu yer burasıdır.
Sondajdan aksesuarlar:
React.js'deki Context API, verileri bileşen ağacının her düzeyinde destek olarak aktarmaya gerek kalmadan bileşenler arasında aktarmanıza olanak tanır. Durumunuzu bir bağlam nesnesinde tanımladığınız ve ardından ona bileşen ağacının herhangi bir yerinden kolayca erişebildiğiniz küresel bir durum yönetim sistemi gibi çalışır. Bunu bir örnekle anlayalım.
Diyagramda görebileceğiniz gibi, birden fazla bileşenin erişeceği verileri saklayan bir bağlam nesnemiz var. Bu veriler API'lerden veya üçüncü taraf hizmetlerden alınır. Herhangi bir bileşende bu bağlam verilerine erişmeden önce, bu veriyi gerektiren tüm bileşenleri bir bağlam sağlayıcı bileşenine sarmamız gerekir.
Yalnızca gezinme ve profil bileşenlerindeki verilere erişmemiz gerekiyorsa uygulama bileşenini tamamlamamıza gerek yoktur. İlgili bileşenleri ContextProvider
ile sardıktan sonra, onu tüketen herhangi bir bileşendeki bağlam verilerine doğrudan erişebilirsiniz. Henüz anlamadıysanız endişelenmeyin; Hadi kodun içine dalalım ve onu çalışırken görelim.
Öncelikle Vite.js kullanarak bir React uygulaması oluşturalım. Projeyi kurmak için aşağıdaki komutları kopyalamanız yeterlidir.
npm create vite@latest
cd project_name // to change to project directory npm install npm run dev
Daha sonra tarayıcınızda geliştirme sunucunuzu http://localhost:5173
açabilirsiniz.
Öncelikle gerekli klasörleri oluşturalım. İşte projemizin klasör yapısı.
src | components | context
Components klasöründe Profile.jsx
dosyasını oluşturup aşağıdaki kodu ekleyelim.
import React from 'react' const Profile = () => { return ( <div>Profile</div> ) } export default Profile
Bileşenler klasöründe Navbar.jsx
adında bir bileşen daha oluşturun.
import Profile from './Profile' const Navbar = () => { return ( <nav style={{ display: "flex", justifyContent: "space-between", alignItems: "center", width: "90%", height: "10vh", backgroundColor: theme === "light" ? "#fff" : "#1b1b1b", color: theme === "light" ? "#1b1b1b" : "#fff", border: "1px solid #fff", borderRadius: "5px", padding: "0 20px", marginTop: "40px", }}> <h1>LOGO</h1> <Profile /> </nav> ) } export default Navbar
Bu <Navbar />
bileşenini App.jsx
dosyasına aktaralım.
import Navbar from "./components/Navbar"; function App() { return ( <main style={{ display: "flex", flexDirection: "column", justifyContent: "start", alignItems: "center", height: "100vh", width: "100vw", }} > <Navbar /> </main> ); } export default App;
Yani temel olarak, <Profile />
bileşeni <Navbar />
'ın çocuğudur ve <Navbar />
<App />
bileşeninin çocuğudur.
context
klasöründe UserContext.jsx
dosyasını oluşturalım. Aşağıdaki kodu dosyaya ekleyin.
import { createContext, useEffect, useState } from "react"; export const UserContext = createContext(); export const UserProvider = ({ children }) => { const [user, setUser] = useState(null); const fetchUserData = async (id) => { const response = await fetch( `https://jsonplaceholder.typicode.com/users/${id}` ).then((response) => response.json()); console.log(response); setUser(response); }; useEffect(() => { fetchUserData(1); }, []); return ( <UserContext.Provider value={{ user, fetchUserData }} > {children} </UserContext.Provider> ); };
createContext
kullanarak boş bir UserContext
nesnesi oluşturuyoruz. react
içe aktardığımızdan emin oluyoruz. Bağlam nesnesinin içine varsayılan değerler ekleyebiliriz ancak şimdilik onu boş tutuyoruz.
UserContext.Provider
gibi UserContext
kullanan bir sağlayıcıyı döndüren UserProvider
oluşturuyoruz. Çocuk bileşenlerini sarar ve değerde, çocuk bileşenlerde kullanmak istediğimiz her şeyi iletebiliriz.
fetchUserData
işlevi id
kabul eder ve kullanıcı verilerini getirmek için bu kimliği kullanır. Daha sonra yanıtı user
durumunda saklarız.
useEffect
fetchUserData
işlevini çağırıyoruz, böylece sayfa yüklenirken işlevi çağırır ve verileri user
durumunda enjekte eder.
Şimdi bu bağlamı <App />
bileşeninde kullanalım. <NavBar />
bileşenini <UserProvider />
kullanarak sarın; aşağıdaki kodla aynı:
<UserProvider> <Navbar /> </UserProvider>
<Profile />
bileşeninde user
durumunu kullanalım. Bunun için useContext
kancasını kullanacağız. Bu, UserContext
alır ve UserProvider
ilettiğimiz user
durumu ve fetchUserData
işlevi gibi değerleri sağlar. Unutmayın, zaten sağlayıcıyla sarılmış olan <Navbar />
bileşeninin içinde olduğundan <Profile />
bileşenini sarmalamamıza gerek yok.
Profile.jsx
dosyasını açın ve aşağıdaki kodu ekleyin.
const { user } = useContext(UserContext); if (user) { return ( <span style={{ fontWeight: "bold", }} > {user.name} </span> ); } else { return <span>Login</span>; }
Burada UserContext
user
durumunu kullanıyoruz. user
varsa kullanıcı adını görüntüleyeceğiz, aksi takdirde yalnızca giriş mesajını görüntüleyeceğiz. Şimdi çıktıyı görüyorsanız gezinme çubuğu bileşeninde bir kullanıcı adı bulunmalıdır. Herhangi bir bileşenin bağlamındaki herhangi bir durumu doğrudan bu şekilde kullanabiliriz. Bu durumu kullanan bileşenin <Provider />
içine sarılması gerekir.
Ayrıca birden fazla bağlam da kullanabilirsiniz. Aşağıdaki örnekte gösterildiği gibi sağlayıcı bileşenlerini başka bir sağlayıcı bileşeninin içine sarmanız yeterlidir.
<ThemeProvider> <UserProvider> <Navbar /> </UserProvider> </ThemeProvider>
Yukarıdaki örnekte tema durumunu yöneten <ThemeProvider />
kullanıyoruz.
Birden fazla içerik sağlayıcı kullanmanın tam örneğini görmek için yukarıdaki youtube videosunu izleyebilirsiniz.
Bağlam API'sini birden çok bileşende kullandığınızda ortaya çıkan bir sorun vardır. Context API'de durum veya değer değiştiğinde, tüm bileşenler değiştirilen durumu kullanmasa bile söz konusu bağlama abone olan tüm bileşenleri yeniden işler. Bu yeniden oluşturma sorununu anlamak için sayım değerlerini depolamak ve görüntülemek için bağlamı kullanan bir <Counter />
bileşeni oluşturalım.
Aşağıdaki örneğe göz atın. Components klasöründe Counter.jsx
dosyası oluşturup aşağıdaki kodu yapıştırabilirsiniz.
import { createContext, memo, useContext, useState } from "react"; const CountContext = createContext(); const CountProvider = ({ children }) => { const [count, setCount] = useState(0); return ( <CountContext.Provider value={{ count, setCount }}> {children} </CountContext.Provider> ); }; function CountTitle() { console.log("This is Count Title component"); return <h1>Counter Title</h1>; } function CountDisplay() { console.log("This is CountDisplay component"); const { count } = useContext(CountContext); return <div>Count: {count}</div>; } function CounterButton() { console.log("This is CounterButton component"); const { count, setCount } = useContext(CountContext); return ( <> <CountTitle /> <CountDisplay /> <button onClick={() => setCount(count + 1)}>Increase</button> </> ); } export default function Counter() { return ( <CountProvider> <CounterButton /> </CountProvider> ); }
Yukarıdaki kodda:
CountContext
nesnesi oluşturuyoruz createContext.
CountProvider,
sayım değerlerini saklayacak bir durumumuz var. count
ve setCount
metodunu alt bileşenlere value prop aracılığıyla gönderiyoruz.
Bireysel bileşenlerin kaç kez yeniden oluşturulduğunu görmek için bileşenleri ayrı ayrı oluşturduk.
<CountTitle />
: Bu bileşen yalnızca başlığı görüntüler ve bağlamdaki herhangi bir değeri bile kullanmaz.
<CountDisplay />
: Bu bileşen sayım değerlerini görüntüler ve bağlamdan count
durumunu kullanır.
<CounterButton />
: Bu bileşen, hem yukarıdaki bileşeni hem de setCount
kullanarak sayım değerlerini artıran bir düğmeyi işler.
Son olarak <CounterButton />
bileşenini CountProvider
bileşeni içerisine sarıyoruz ki diğer bileşenler de count değerlerine erişebilsin.
Şimdi, kodu çalıştırıp Increase
düğmesini tıklarsanız, günlüklerde, durum her değiştiğinde her bileşenin yeniden oluşturulduğunu göreceksiniz. <CountTitle />
sayım değerlerini bile kullanmıyor, henüz yeniden oluşturuluyor. Bunun nedeni, <CountTitle />
'nin <CounterButton />
ana bileşeninin count değerini kullanması ve güncellemesi ve bu nedenle yeniden oluşturmasıdır.
Bu davranışı nasıl optimize edebiliriz? Cevap memo
dır. React memo
bir bileşenin özellikleri değişmediğinde yeniden oluşturma işlemini atlamanıza olanak tanır. <CountTitle />
bileşeninden sonra aşağıdaki satırı ekleyelim.
const MemoizedCountTitle = React.memo(CountTitle)
Şimdi <CountTitle />
bileşenini render ettiğimiz <CounterButton />
bileşeninde, aşağıdaki koddaki gibi <CountTitle />
yerine <MemoizedCountTitle />
yazın:
<> <MemoizedCountTitle /> <CountDisplay /> <button onClick={() => setCount(count + 1)}>Increase</button> </>
Şimdi, eğer sayıyı arttırıp logları kontrol ederseniz, artık <CountTitle />
bileşenini render etmediğini görebilmelisiniz.
Redux
daha öngörülebilir durum geçişlerine sahip karmaşık durum yönetimi için bir durum yönetimi kitaplığıdır. Bağlam API'si basit durum yönetimi ve verileri bileşen ağacından detay detaylandırması olmadan geçirmek için tasarlanmıştır. Peki hangisini ne zaman seçmeli?
Ayrıca devlet yönetimi için de popüler bir seçenek olan bir kütüphane daha var. React Geri Tepmesi .
React Recoil hakkında daha fazla bilgi edinmek istiyorsanız yorumlarda bana bildirin; geri bildirimlerinize dayanarak bu konuyla ilgili derinlemesine eğitimler oluşturacağım.
React.js
Context API, birden fazla bileşenin durumlarını yönetmenin güçlü ve etkili bir yolunu sunarak pervane sondajı sorununu etkili bir şekilde ele alır. Context API'yi kullanarak kodunuzu basitleştirebilir, gereksiz yeniden oluşturmaları azaltabilir ve genel uygulama performansını artırabilirsiniz.
Context API basit durum yönetimi için ideal olsa da, daha karmaşık uygulamalar Redux
veya React Recoil
gibi diğer durum yönetimi kitaplıklarının kullanılmasından yararlanabilir. Bu araçların ne zaman ve nasıl kullanılacağını anlamak, daha sürdürülebilir ve ölçeklenebilir React uygulamaları oluşturmanıza olanak sağlayacaktır.
Bu makaleyi okuduğunuz için teşekkürler, umarım faydalı bulmuşsunuzdur. React, Redux ve Next.js kullanarak projeler öğrenmek ve oluşturmak ilginizi çekiyorsa YouTube kanalımı buradan ziyaret edebilirsiniz: CodeBucks
Okumak isteyebileceğiniz diğer yazılarım:
Next.js'de Lenis ve GSAP ile düzgün kaydırma nasıl uygulanır?
Denemeniz Gereken En Popüler 10 VS Code Teması
Kişisel blogumu ziyaret edin: DevDreaming