İlgisiz bileşen katmanları arasından prop geçirmek zahmetli bir iştir. Bir gün yeni bir özellik yayınlıyorsunuz, ertesi gün ise sadece tek bir prop'un adını değiştirmek için altı dosyayı düzenlemek zorunda kalıyorsunuz. İşte prop drilling tam olarak budur: bir üst bileşende veri vardır, derinlerdeki bir çocuk bileşenin buna ihtiyacı vardır ve aradaki her bileşen bir kuryeye dönüşür. Uygulama hala çalışır ancak kod tabanı kırılganlaşır. Aradaki bir katmanı kaldırırsanız, ağacın yarısı çöker. Bir tipi değiştirirseniz, TypeScript üç farklı dizinde hata verir. React Context API, bu aracıları tamamen ortadan kaldırmak için vardır.
Prop Drilling Aslında Neye Benzer
Standart bir uygulama yapısı hayal edin. Mevcut kullanıcıyı çeken bir App bileşeniniz var. App içinde bir Layout bulunur, Layout içinde bir Sidebar yer alır, Sidebar içinde bir Navigation bulunur ve son olarak Navigation içinde kullanıcı nesnesine gerçekten ihtiyaç duyan UserAvatar bileşeni bulunur.
Kodunuz şu hale gelir:
function App() {
const user = { name: 'Aarav', role: 'admin' };
return <Layout user={user} />;
}
function Layout({ user }) {
return <Sidebar user={user} />;
}
function Sidebar({ user }) {
return <Navigation user={user} />;
}
function Navigation({ user }) {
return <UserAvatar user={user} />;
}
Layout, Sidebar ve Navigation bileşenleri, o kullanıcı nesnesiyle sadece onu aşağıya iletmek dışında hiçbir şey yapmazlar. Kendilerine ait olmayan propları biriktirirler, arayüzleri (interface) şişer ve onları test etmek, asla dokunmadıkları verileri mock'lamayı gerektirir. Asıl sorun, bu durumun ne kadar hızlı yayıldığıdır. Bir isLoggedIn bayrağı, bir locale dizisi veya bir theme değeri ekleyin; aynı döngü tekrarlanır.
Context API Oyunun Kurallarını Nasıl Değiştirir
Context API'yi bir WiFi yönlendiricisi (router) gibi düşünün. Her cihaza ulaşmak için her odadan uzun kablolar geçirmek yerine, yönlendirici sinyali havadan gönderir. Menzil içindeki herhangi bir cihaz doğrudan bağlanabilir. React terimleriyle konuşursak; yönlendirici Provider, sinyal state veya veriniz, cihaz ise useContext çağıran herhangi bir iç içe geçmiş bileşendir.
Kurulumun üç hareketli parçası vardır:
React.createContext()veri kanalını oluşturur.- Provider, ağacınızın bir bölümünü sarmalar ve bir değer iletir.
useContexthook'u, alt bileşenlerin ara proplara dokunmadan bu değeri almasını sağlar.
Hala bir ağaç yapınız vardır, ancak kök ile yaprak arasındaki dalların artık bir kurye sözleşmesi üzerinde anlaşmasına gerek kalmaz.
Sıfırdan Bir Context Oluşturmak
Çoğu uygulamanın bir noktada açık veya koyu moda ihtiyacı olacağı için, tema ayarlarıyla somut bir örnek oluşturalım.
Önce context nesnesini oluşturun. Bu, boru hattıdır:
import { createContext, useState, useMemo } from 'react';
const ThemeContext = createContext(null);
export function ThemeProvider({ children }) {
const [theme, setTheme] = useState('light');
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
{children}
</ThemeContext.Provider>
);
}
export default ThemeContext;
Ardından uygulamanızı provider ile sarmalayın. Genellikle bu işlem kök dizine yakın bir yerde yapılır:
import { ThemeProvider } from './ThemeContext';
function App() {
return (
<ThemeProvider>
<Layout />
</ThemeProvider>
);
}
Artık herhangi bir alt bileşen sinyale doğrudan bağlanabilir. İşte kullanıcı arayüzünün derinliklerine gömülmüş bir açma/kapama düğmesi:
import { useContext } from 'react';
import ThemeContext from './ThemeContext';
function ThemeToggle() {
const { theme, setTheme } = useContext(ThemeContext);
return (
<button
onClick={() => setTheme(prev => prev === 'light' ? 'dark' : 'light')}
>
Current theme: {theme}
</button>
);
}
Layout, Sidebar ve Navigation bileşenlerinin theme prop'unu hiç görmediğine dikkat edin. Normal bir şekilde render edilirler ve ThemeToggle, ihtiyacı olanı doğrudan context'ten alır. Bağlantılar dışarıdan görünmez, ki asıl amaç da budur.
Context Aslında Nerelerde Kullanılmalı
Context, birçok uzak bileşenin paylaştığı ancak tek bir üst bileşenin temiz bir şekilde sahiplenmediği veriler için en iyi sonucu verir. İyi adaylar şunlardır:
- Tema ayarları gibi açık veya koyu mod, vurgu renkleri veya yazı tipi ölçeklendirmesi.
- Kimlik doğrulama durumu gibi mevcut kullanıcı nesnesi, giriş durumu veya oturum süresi.
- Uluslararasılaştırma için dil ve yerel ayarlar (locale).
- Bir header rozeti, mini sepet açılır menüsü ve ödeme sayfası arasında senkronize kalması gereken alışveriş sepeti verileri.
Her yerel state'i Context'e boşaltma dürtüsüne karşı koyun. İki seviye aşağıdaki bir form girişi, küresel bir yayına ihtiyaç duymaz. Context'i gerçekten tüm uygulamayı ilgilendiren durumlar için saklayın ve geri kalanını normal proplar olarak bırakın.
Performans Tuzakları ve Bunlardan Kaçınma Yolları
Context bedava değildir. Bir context değeri güncellendiğinde, ilgilendikleri değer dilimi değişmese bile, o context'e bağlı olan her bileşen yeniden render edilir. Klasik hata, her üst bileşen render edildiğinde Provider'a yeni bir nesne (object literal) fırlatmaktır.
Tema örneğimizde, ThemeProvider kendi üst bileşeni güncellendiği için her yeniden render edildiğinde, { theme, setTheme } ifadesi yepyeni bir nesne oluşturur. React yeni bir referans görür ve tüm tüketiciler güncellenir. Eğer temanız nadiren değişiyor ancak uygulama durumunuz sık değişiyorsa, ihtiyacınız olmayan render'lar için bedel ödüyorsunuz demektir.
Çözüm iki aşamalıdır.
Context'lerinizi güncelleme sıklığına göre ayırın. Giriş yapıldığında bir kez değişen bir UserContext, her birkaç saniyede bir güncellenen bir NotificationContext ile aynı provider'ı paylaşmamalıdır. Statik verilerin, değişken verilerle aynı yeniden render trenine binmemesi için onları ayrı tutun.
Değer bir nesne veya dizi olduğunda, değeri useMemo ile sarmalayın. React'e kararlı bir referans verin:
export function ThemeProvider({ children }) {
const [theme, setTheme] = useState('light');
const value = useMemo(() => ({ theme, setTheme }), [theme]);
return (
<ThemeContext.Provider value={value}>
{children}
</ThemeContext.Provider>
);
}
Now the object identity only shifts when theme actually changes. Descendant components that care about the context but are shielded by React.memo further down will skip the work.
Mistakes That Waste Your Time
The two errors that still show up in production code are easy to prevent.
First, forgetting to export the context itself. If you only export the Provider wrapper and keep the context object private, a developer writing a new feature cannot call useContext without refactoring your module. Export the context so consumers can import both the provider and the consumer hook cleanly.
Second, calling useContext outside the corresponding Provider. If ThemeToggle renders in a branch of the tree that is not wrapped in ThemeProvider, the hook returns the default value passed to createContext, or undefined if you passed none. This leads to silent failures like cannot read property of undefined. You can guard against this by assigning a sensible default or throwing a clear error early in the hook call.
Context vs Redux: Keep It Simple
You do not always need Redux. For medium-sized projects, Context paired with useState or useReducer covers the bulk of state sharing. Redux shines when you need time-travel debugging, complex middleware, or global transactions that must roll back in sequence. If your entire state story is a user object, a theme string, and a cart array, a store library adds boilerplate you will never leverage.
That said, Context is not a full state management system on its own. It does not give you a single global snapshot, and it does not batch updates across unrelated contexts. Use it as a replacement for prop drilling, not as an operating system for your entire data layer.
The Real Takeaway
Stop threading props through components that do not care about them. Create focused contexts for the data that actually spans your tree, wrap providers high enough to cover the consumers, and always stabilize the value object when you are passing collections or functions. Context API keeps yourReact code direct: props stay local, global data travels wirelessly, and your component boundaries stay clean.
