useContext — este un hook React care oferă componentelor funcționale acces direct la datele din contextul creat prin createContext. Contextul în React rezolvă problema props drilling — transmiterea de props prin multiple componente intermediare care nu folosesc ele înăsele aceste date. Conform React Documentation (2025), useContext primește obiectul de context și returnează valoarea curentă stabilită de cel mai apropiat Provider mai sus în arborele de componente. Când valoarea din Provider se schimbă, toate componentele care folosesc useContext se re-renderizează automat.
Principalele
useContext — este un hook adăugat în React 16.8 împreună cu celelalte hookuri, care permite citirea valorii din contextul React. Contextul este un mecanism încorporat în React, destinat transmiterii de date prin arborele de componente fără a fi nevoie să transmiți props la fiecare nivel manual. useContext înlocuiește componenta Consumer din vechiul Context API și face codul mai concis și mai lizibil.
Scenariile tipice de utilizare a contextului includ teme de design (luminoasă/întunecată), setări regionale și traduceri (i18n), autentificarea utilizatorului, setările aplicației și orice alte date globale de care au nevoie multe componente la diferite niveluri de imbricare. Echipa React recomandă utilizarea contextului pentru date care sunt globale pentru subarborele de componente, dar nu pentru întreaga aplicație.
Conform React Team — Context documentation (2025), utilizarea incorectă a contextului este una dintre principalele cauze ale problemelor de performanță în aplicațiile React. Fiecare schimbare a valorii în Provider provoacă re-renderizarea tuturor consumatorilor, indiferent de ce parte a datelor s-a schimbat. Optimizarea prin useMemo și separarea contextelor rezolvă această problemă.
import { createContext, useContext } from 'react';
// Creează contextul cu valoare implicită
const ThemeContext = createContext('luminos');
function ThemedButton() {
const theme = useContext(ThemeContext);
return <button className={`btn-${theme}`}>Click</button>;
}
Mecanismul contextului în React este implementat prin tiparul Provider-Consumer. createContext returnează un obiect cu două entități: Provider — componenta care transmite valoarea, și obiectul de context în sine folosit în useContext. Providerul se montează în arborele de componente și transmite valoarea tuturor elementelor copil indiferent de adâncimea imbricării.
Când React întâlnește un apel useContext, urcă prin arborele fiber în căutarea celui mai apropiat Provider pentru acel context. Dacă Providerul este găsit, se returnează valoarea sa. Dacă Providerul nu este găsit, se returnează valoarea implicită transmisă la createContext. Această căutare are loc la fiecare randare, dar datorită memizării nodurilor fiber este foarte rapidă și nu afectează performanța.
Conform React — Context internals (2024), implementarea internă a useContext folosește o listă înlănțuită de hookuri, similar cu useState. Fiecare hook păstrează o referință la nodul fiber, ceea ce permite React să determine rapid care Provider corespunde acelui context. Dacă Providerul actualizează valoarea, React marchează toate nodurile fiber care folosesc acest context pentru re-renderizare.
Componentele Provider pot fi îmbricate una în alta, creând o ierarhie de contextele. Fiecare Provider copil suprascrie valoarea părintelui pentru subarborele său. Acest lucru este util când pe un ecran este nevoie de o temă luminoasă, iar într-o fereastră modală imbricată — de una întunecată. useContext returnează întotdeauna valoarea celui mai apropiat Provider în susul arborelui.
const UserContext = createContext(null);
const ThemeContext = createContext('luminos');
function App() {
return (
<UserContext.Provider value={{ name: 'Alice' }}>
<ThemeContext.Provider value='dark'>
<Profile />
</ThemeContext.Provider>
</UserContext.Provider>
);
}
Funcția createContext(defaultValue) creează un obiect de context. Parametrul defaultValue este folosit când componenta apelează useContext, dar mai sus în arbore nu există un Provider corespunzător. Fără defaultValue, useContext va returna undefined, ceea ce poate duce la erori neașteptate. Se recomandă să transmiți întotdeauna o valoare implicită semnificativă sau null.
Crearea unui provider personalizat este un tipar comun pentru încapsularea logicii contextului. În interiorul unui astfel de provider se stochează starea (prin useState sau useReducer) și este oferită prin prop-ul value al Providerului. Acest lucru permite ascunderea detaliilor de implementare de componentele consumatoare și centralizarea logicii de gestionare a contextului într-un singur loc.
// Provider personalizat cu gestionarea stării
const AuthContext = createContext(null);
function AuthProvider({ children }) {
const [user, setUser] = useState(null);
const login = useCallback(async (email, pass) => {
const u = await loginApi(email, pass);
setUser(u);
}, []);
return (
<AuthContext.Provider value={{ user, login }}>
{children}
</AuthContext.Provider>
);
}
În componentele funcționale, useContext este singurul mod de a obține acces la context. Acesta înlocuiește componenta Consumer din vechiul Context API, care necesită tiparul render-prop: <ThemeContext.Consumer>{value => ...}</ThemeContext.Consumer>. useContext face codul mai liniar și mai lizibil, mai ales când se lucrează cu mai multe contextele într-o singură componentă.
Când folosești mai multe contextele într-o singură componentă, apelează pur și simplu useContext de mai multe ori pentru fiecare context. Fiecare apel returnează valoarea Providerului corespunzător. Ordinea apelurilor nu contează, deoarece fiecare context este o entitate independentă. React optimizează apelurile multiple prin același sistem de referințe fiber.
function Dashboard() {
const { user } = useContext(AuthContext);
const theme = useContext(ThemeContext);
const { locale } = useContext(I18nContext);
return (
<div className={`dashboard-${theme}`}>
<h1>{locale.greeting}, {user.name}</h1>
</div>
);
}
Alegerea între useContext și Redux depinde de scara și complexitatea gestionării stării. useContext + useReducer este o înlocuire ușoară a Redux pentru aplicații mici și medii. Nu necesită instalarea unei biblioteci externe, este mai ușor de învățat și suficient pentru majoritatea sarcinilor. Redux este justificat când este necesară o arhitectură strictă cu middleware, instrumente de dezvoltare și actualizări imutabile.
Principalul avantaj al Redux față de useContext este optimizarea re-renderizărilor. Îm mod implicit, la schimbarea valorii în Provider, toți consumatorii de context se re-renderizează. Redux cu useSelector și shallowEqual permite componentelor să se aboneze doar la anumite părți ale stării, ceea ce reduce semnificativ numărul de re-renderizări în aplicațiile mari. Contextul poate fi de asemenea optimizat prin împărțirea în mai multe contextele mici.
| Criteriu | useContext | Redux |
|---|---|---|
| Complexitate | Fără dependențe externe | Necesită configurare store și middleware |
| Re-renderizări | Toți consumatorii la orice schimbare | Doar abonații la un anumit slice |
| DevTools | React DevTools | Redux DevTools cu time-travel |
| Middleware | Nu este suportat | Redux Thunk, Saga, Observable |
| Când să alegi | Aplicații medii, 3-5 contexte | Aplicații mari cu logică de afaceri complexă |
Conform Redux maintainers — When to use Redux (2024), 70% din aplicațiile React nu au nevoie de Redux. Dacă ai mai puțin de 50 de componente și starea nu are o logică complexă cu cache, debounce și efecte secundare — useContext + useReducer este mai mult decât suficient. Redux adaugă boilerplate și trebuie folosit cu discernământ.
Cea mai frecventă greșeală este recrearea obiectului value la fiecare randare a Providerului. Dacă transmiți în Provider value={{ user, login }}, la fiecare randare a Providerului se creează un obiect nou, ceea ce provoacă re-renderizarea tuturor consumatorilor, chiar dacă datele nu s-au schimbat. Soluția — memorizarea value prin useMemo sau folosirea de contexte separate pentru datele care se schimbă frecvent și rar.
// ❌ Obiect nou la fiecare randare — toți consumatorii se re-renderizează
<AuthContext.Provider value={{ user, login }}>{children}</AuthContext.Provider>
// ✅ Valoare memorizată — re-renderizare doar când se schimbă utilizatorul sau login
const authValue = useMemo(() => ({ user, login }), [user, login]);
<AuthContext.Provider value={authValue}>{children}</AuthContext.Provider>
Pentru a rezolva problema „contextului mare”, împarte starea globală în grupuri logice: AuthContext, ThemeContext, I18nContext. Fiecare context răspunde pentru domeniul său și se actualizează independent. Aceasta este mai simplu decât să încerci să optimizezi un singur context gigantic prin useMemo și oferă un comportament mai previzibil al re-renderizărilor.
Întrebări frecvente
Da, dacă transmiți o funcție-mutator în value a Providerului. Tiparul tipic este stocarea stării în Provider și transmiterea atât a datelor, cât și a funcțiilor pentru actualizarea lor prin useContext. Componentele copil apelează aceste funcții, iar schimbarea stării în Provider actualizează automat toți consumatorii. Aceasta este o înlocuire de bază pentru Redux în aplicații mici.
Pentru scenarii simple, useContext este mai rapid datorită lipsei de overhead din partea store și middleware. Dar la actualizări frecvente cu un număr mare de consumatori, Redux câștigă, deoarece selectorii săi (useSelector) se abonează la părți specifice ale stării, în timp ce useContext re-renderizează toți consumatorii la orice schimbare. Pentru aplicații cu frecvență ridicată de actualizare (animații, real-time) alegerea ar trebui să fie Redux sau biblioteci specializate.
Nu. useContext, ca toate hookurile, poate fi apelat doar în interiorul unei componente funcționale React sau al unui hook personalizat. Dacă ai nevoie de valoarea contextului într-o funcție obișnuită (de exemplu, într-un utilitar sau serviciu), transmite-o ca parametru din componentă sau folosește un modul separat cu stare globală în afara React.
Tipizarea contextului în TypeScript constă în specificarea tipului în createContext: createContext<AuthContextType | null>(null). Aceasta garantează că useContext(AuthContext) returnează o valoare de tip corect. Un tipar convenabil este crearea unui hook personalizat useAuth care apelează useContext, verifică null și aruncă o eroare ușor de înțeles: „useAuth must be used within AuthProvider”.
Cea mai frecventă cauză este că componenta consumatoare se află în afara Providerului corespunzător. Verifică dacă Providerul înfășoară întreaga subarbore în care este folosit useContext. A doua cauză este transmiterea Providerului unui alt obiect de context: dezvoltatorul creează contextul prin apelul createContext, dar folosește useContext cu o altă instanță de createContext.
Rezumat
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și