useContext: esența, hookul de acces la context și providerii în React

Autor: IT Sectr Publicat: 2026-07-04 Timp de citire: 9 min

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 — hook pentru citirea valorii din contextul React fără props drilling.
  • createContext — creează un obiect de context cu o valoare implicită și o componentă Provider.
  • Provider — componentă-ambalaj care transmite valoarea contextului tuturor elementelor copil.
  • Re-renderizare — schimbarea valorii în Provider provoacă re-renderizarea tuturor consumatorilor de context.
  • Omiterea componentelor intermediare — useContext permite transmiterea datelor prin mai multe niveluri de imbricare.

Ce este useContext în React

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ă.

jsx
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>;
}

Cum funcționează contextul în React

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.

Provider și contextele imbricate

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.

jsx
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>
    );
}

Crearea unui provider cu createContext

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.

jsx
// 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>
    );
}

Folosirea useContext în componentele copil

Î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.

jsx
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>
    );
}

useContext vs Redux: când să alegi ce

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.

CriteriuuseContextRedux
ComplexitateFără dependențe externeNecesită configurare store și middleware
Re-renderizăriToți consumatorii la orice schimbareDoar abonații la un anumit slice
DevToolsReact DevToolsRedux DevTools cu time-travel
MiddlewareNu este suportatRedux Thunk, Saga, Observable
Când să alegiAplicații medii, 3-5 contexteAplicaț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.

Greșeli tipice cu useContext

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.

  • Re-renderizări inutile — obiect value nou la fiecare randare a Providerului. Folosește useMemo pentru memorizarea value.
  • Context prea mare — un singur Provider cu zeci de câmpuri face ca toate componentele copil să se re-renderizeze la schimbarea oricărui câmp. Împarte în mai multe contexte după înțeles.
  • Lipsa defaultValue — dacă Providerul nu este găsit, useContext returnează defaultValue, iar dacă este undefined — fiecare apel va eșua cu TypeError.
  • Provideri imbricați de același tip — suprascrierea contextului la niveluri adânci poate deruta și duce la valori neașteptate.
jsx
// ❌ 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

Pot schimba contextul dintr-o componentă copil?

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.

Ce este mai rapid — useContext sau Redux?

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.

Pot folosi useContext în afara unei componente React?

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.

Cum funcționează useContext cu TypeScript?

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”.

De ce useContext returnează undefined deși Providerul există?

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

  • useContext — hook pentru citirea valorii din contextul React, eliminând necesitatea props drilling.
  • createContext — creează un obiect de context cu Provider pentru transmiterea datelor și defaultValue pentru cazul fără Provider.
  • Memorizarea value — folosește useMemo pentru value în Provider pentru a evita re-renderizările inutile ale consumatorilor.
  • Separarea contextelor — împarte starea globală în mai multe contexte mici după grupuri logice.
  • Ierarhia Providerilor — se pot imbrica Provideri de același tip pentru a suprascrie valoarea într-o parte a arborelui.
  • useContext + useReducer — înlocuire ușoară a Redux pentru aplicații medii fără dependențe externe.
  • Nu înlocuiește Redux — pentru logică complexă cu middleware și actualizări frecvente alege Redux cu selectori.

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.

Discutați proiectul

Citiți și