બિનજરૂરી components ના સ્તરો દ્વારા props પસાર કરવા એ કંટાળાજનક કામ છે. એક દિવસ તમે કોઈ ફીચર શિપ કરી રહ્યા હોવ છો, અને બીજા જ દિવસે માત્ર એક સિંગલ prop નું નામ બદલવા માટે તમારે છ ફાઇલો એડિટ કરવી પડે છે. ટૂંકમાં કહીએ તો આ જ 'prop drilling' છે: એક પેરેન્ટ પાસે ડેટા છે, એક ઊંડા ચાઇલ્ડને તેની જરૂર છે, અને તેમની વચ્ચેના દરેક component એક કુરિયર બની જાય છે. એપ હજી પણ ચાલે છે, પરંતુ કોડબેઝ નાજુક (brittle) બની જાય છે. વચ્ચેનું એક લેયર હટાવો, અને અડધું ટ્રી (tree) તૂટી જાય છે. એક ટાઇપ બદલો, અને TypeScript ત્રણ ડિરેક્ટરીઓમાં ભૂલો બતાવવા લાગે છે. React Context API આ મધ્યસ્થીઓને સંપૂર્ણપણે દૂર કરવા માટે અસ્તિત્વ ધરાવે છે.
Prop Drilling ખરેખર કેવું દેખાય છે
એક સ્ટાન્ડર્ડ એપ શેલની કલ્પના કરો. તમારી પાસે એક App component છે જે વર્તમાન યુઝરને ફેચ (fetch) કરે છે. App ની અંદર Layout રહે છે, Layout ની અંદર Sidebar છે, Sidebar ની અંદર Navigation છે, અને અંતે Navigation ની અંદર તમને UserAvatar મળે છે જેને ખરેખર યુઝર ઓબ્જેક્ટની જરૂર છે.
તમારો કોડ આવો દેખાશે:
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, અને Navigation તે યુઝર ઓબ્જેક્ટ સાથે કંઈ જ નથી કરતા, માત્ર તેને નીચે મોકલે છે. તેઓ એવા props એકઠા કરે છે જે તેમના પોતાના નથી, તેમના ઇન્ટરફેસ ફૂલી જાય છે, અને તેમને ટેસ્ટ કરવા માટે એવો ડેટા મોક (mock) કરવો પડે છે જેને તેઓ ક્યારેય સ્પર્શ પણ કરતા નથી. અસલી સમસ્યા એ છે કે આ કેટલી ઝડપથી ફેલાય છે. એક isLoggedIn ફ્લેગ, locale સ્ટ્રિંગ, અથવા theme વેલ્યુ ઉમેરો, અને આ જ પ્રક્રિયા ફરીથી પુનરાવર્તિત થાય છે.
Context API કેવી રીતે રમત બદલી નાખે છે
Context API ને WiFi રાઉટરની જેમ વિચારો. દરેક ઉપકરણ સુધી પહોંચવા માટે દરેક રૂમમાંથી લાંબા કેબલ પસાર કરવાને બદલે, રાઉટર હવામાં સિગ્નલ મોકલે છે. રેન્જમાં હોય તેવું કોઈપણ ઉપકરણ સીધું કનેક્ટ થઈ શકે છે. React ની ભાષામાં, રાઉટર એ Provider છે, સિગ્નલ એ તમારો સ્ટેટ અથવા ડેટા છે, અને ઉપકરણ એ કોઈપણ નેસ્ટેડ component છે જે useContext નો ઉપયોગ કરે છે.
તેના સેટઅપમાં ત્રણ મુખ્ય ભાગો છે:
React.createContext()ડેટા ચેનલ બનાવે છે.- Provider તમારા ટ્રીના એક વિભાગને આવરી લે છે અને વેલ્યુ ટ્રાન્સમિટ કરે છે.
useContextહૂક (hook) વચગાળાના props ને અડક્યા વગર વંશજોને તે વેલ્યુ મેળવવાની મંજૂરી આપે છે.
તમારી પાસે હજી પણ ટ્રી છે, પરંતુ રૂટ (root) અને લીફ (leaf) વચ્ચેની શાખાઓને હવે કુરિયર કોન્ટ્રાક્ટ પર સહમત થવાની જરૂર નથી.
શૂન્યથી Context બનાવવું
ચાલો થીમ સેટિંગ્સ સાથે એક નક્કર ઉદાહરણ બનાવીએ, કારણ કે મોટાભાગની એપ્સને કોઈને કોઈ સમયે લાઇટ અથવા ડાર્ક મોડની જરૂર હોય છે.
સૌ પ્રથમ, context ઓબ્જેક્ટ બનાવો. આ એક પાઇપ જેવું છે:
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;
ત્યારબાદ તમારી એપ્લિકેશનને provider માં રેપ (wrap) કરો. સામાન્ય રીતે આ રૂટની નજીક થાય છે:
import { ThemeProvider } from './ThemeContext';
function App() {
return (
<ThemeProvider>
<Layout />
</ThemeProvider>
);
}
હવે કોઈપણ વંશજ સીધું સિગ્નલ મેળવી શકે છે. અહીં UI ની અંદર ઊંડે દબાયેલું એક ટોગલ બટન છે:
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, અને Navigation ક્યારેય theme prop ને જોતા નથી. તેઓ સામાન્ય રીતે રેન્ડર થાય છે, અને ThemeToggle તેને જે જોઈએ છે તે સીધું context માંથી મેળવે છે. આ વાયરિંગ બહારથી અદ્રશ્ય છે, જેનો મુખ્ય હેતુ પણ આ જ છે.
Context ખરેખર ક્યાં ઉપયોગી છે
Context ત્યારે શ્રેષ્ઠ રીતે કામ કરે છે જ્યારે ડેટા ઘણા દૂરના components દ્વારા શેર કરવામાં આવતો હોય પરંતુ કોઈ એક પેરેન્ટ પાસે તે વ્યવસ્થિત રીતે ન હોય. સારા ઉમેદવારોમાં સામેલ છે:
- Theme settings જેમ કે લાઇટ અથવા ડાર્ક મોડ, એક્સેન્ટ કલર્સ, અથવા ફોન્ટ સ્કેલિંગ.
- Authentication state જેમ કે વર્તમાન યુઝર ઓબ્જેક્ટ, લોગિન સ્ટેટસ, અથવા સેશન એક્સપાયરી.
- Language and locale સેટિંગ્સ ઇન્ટરનેશનલાઇઝેશન માટે.
- Shopping cart data જે હેડર બેજ, મિની-કાર્ટ ડ્રોપડાઉન અને ચેકઆઉટ પેજ પર સિંક રહેવું જોઈએ.
દરેક લોકલ સ્ટેટને Context માં નાખવાની ઈચ્છા પર કાબૂ રાખો. બે લેવલ નીચેના ફોર્મ ઇનપુટને ગ્લોબલ બ્રોડકાસ્ટની જરૂર નથી. ખરેખર ક્રોસ-કટિંગ બાબતો માટે Context રાખો, અને બાકીનાને સામાન્ય props તરીકે રહેવા દો.
પરફોર્મન્સના છટકબારીઓ અને તેને કેવી રીતે ટાળવા
Context મફત નથી મળતું. જ્યારે context વેલ્યુ અપડેટ થાય છે, ત્યારે તે context સાથે જોડાયેલ દરેક component ફરીથી રેન્ડર (re-render) થાય છે, ભલે તેઓ જે વેલ્યુમાં રસ ધરાવતા હોય તેમાં કોઈ ફેરફાર ન થયો હોય. સામાન્ય ભૂલ એ છે કે દરેક પેરેન્ટ રેન્ડર પર Provider માં એક નવો ઓબ્જેક્ટ લિટરલ (object literal) નાખવો.
આપણા થીમ ઉદાહરણમાં, જ્યારે પણ ThemeProvider તેના પોતાના પેરેન્ટ અપડેટ થવાને કારણે ફરીથી રેન્ડર થાય છે, ત્યારે { theme, setTheme } એક્સપ્રેશન એક બિલકુલ નવો ઓબ્જેક્ટ બનાવે છે. React એક નવો રેફરન્સ જુએ છે, અને દરેક કન્ઝ્યુમર અપડેટ થાય છે. જો તમારી થીમ ભાગ્યે જ બદલાતી હોય પરંતુ તમારી એપ સ્ટેટ વારંવાર બદલાતી હોય, તો તમે એવા રેન્ડર્સ માટે કિંમત ચૂકવી રહ્યા છો જેની તમને જરૂર નથી.
આનો ઉકેલ બેવડો છે.
તમારા contexts ને અપડેટની આવૃત્તિ (frequency) મુજબ અલગ કરો. એક UserContext જે લોગિન દીઠ એકવાર બદલાય છે, તેણે NotificationContext સાથે પ્રોવાઈડર શેર ન કરવો જોઈએ જે દર થોડી સેકન્ડે અપડેટ થાય છે. તેમને અલગ રાખો જેથી સ્ટેટિક ડેટા અસ્થિર (volatile) ડેટાની જેમ જ રી-રેન્ડર ન થાય.
જ્યારે વેલ્યુ ઓબ્જેક્ટ અથવા એરે હોય ત્યારે useMemo માં વેલ્યુને રેપ કરો. React ને એક સ્ટેબલ રેફરન્સ આપો:
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.
