Articolo originale: https://www.freecodecamp.org/news/react-context-for-beginners/

Il contesto di React è uno strumento essenziale da conoscere per qualunque sviluppatore React. Ti consente di condividere facilmente lo stato nelle tue applicazioni.

In questa guida completa, tratteremo cos'è il contesto di React, come usarlo, quando usarlo e quando non, e molto altro.

Anche se non hai mai lavorato prima con il contesto di React, sei nel posto giusto. Imparerai tutto quello che ti serve sapere con semplici esempi passo dopo passo.

Iniziamo!

Sommario

Cosa è il contesto di React?

Il contesto in React ci consente di passare e utilizzare dati in qualunque componente servano nella nostra app React senza usare le prop.

In altre parole, il contesto in React ci consente di condividere dati (lo stato) tra i nostri componenti più facilmente.

Quando dovresti usare il contesto di React?

Il contesto di React è ottimo quando devi passare dati che possono essere usati in qualunque componente nella tua applicazione.

Questi tipi di dato includono:

  • Dati relativi a un tema (come la modalità chiara o scura)
  • Dati utente (l'utente attualmente autenticato)
  • Dati specifici di posizione (come la lingua dell'utente o le impostazioni locali)

I dati che dovrebbero essere inseriti nel contesto di React non dovrebbero essere dati che devono essere aggiornati frequentemente.

Questo perché il contesto non è stato concepito come un intero sistema di gestione dello stato. È stato creato per utilizzare dati più facilmente.

Puoi pensare al contesto di React come l'equivalente di variabili globali per i componenti React.

Quali problemi risolve il contesto di React?

Il contesto di React ci consente di evitare un problema noto come "prop drilling".

Prop drilling descrive una situazione nella quale i dati vengono passati come prop attraverso più livelli di componenti annidati, che non ne hanno bisogno, fino a raggiungere il componente che ne deve fare effettivamente uso.

Ecco un esempio di prop drilling. In questa applicazione abbiamo accesso ai dati di un tema che vogliamo passare come prop a tutti i componenti della nostra applicazione.

Come puoi vedere, anche i diretti discendenti di App, come Header, devono passare i dati del tema ai propri discendenti usando le prop.

export default function App({ theme }) {
  return (
    <>
      <Header theme={theme} />
      <Main theme={theme} />
      <Sidebar theme={theme} />
      <Footer theme={theme} />
    </>
  );
}

function Header({ theme }) {
  return (
    <>
      <User theme={theme} />
      <Login theme={theme} />
      <Menu theme={theme} />
    </>
  );
}

Qual è il problema con questo esempio?

Il problema è che stiamo passando la prop theme attraverso componenti multipli, ai quali non serve direttamente.

Il componente Header non ha bisogno di theme, se non per passarlo ai suoi discendenti. In altre parole, sarebbe meglio che User, Login e Menu utilizzassero i dati in theme direttamente.

Questo è il vantaggio del contesto di React, possiamo evitare interamente l'uso delle prop, di conseguenza evitando il problema del prop drilling.

Come uso il contesto di React?

Il contesto è una API integrata in React, a partire dalla versione 16.

Ciò significa che possiamo creare e utilizzare il contesto direttamente importando React in qualunque progetto React.

Ci sono quattro passaggi per usare il contesto di React:

  1. Crea il contesto usando il metodo createContext.
  2. Prendi il contesto che hai creato e racchiudi all'interno del fornitore di contesto (context provider) la tua alberatura di componenti .
  3. Inserisci qualunque valore desideri nel tuo fornitore di contesto usando la prop value.
  4. Utilizza quel valore all'interno di qualsiasi componente usando l'utilizzatore di contesto  (context consumer).

Tutto ciò può sembrare confuso, ma è più semplice di quanto pensi.

Diamo un'occhiata a un esempio molto semplice. Dal componente App passiamo il nostro nome tramite contesto e lo leggiamo in un componente annidato: User.

import React from 'react';

export const UserContext = React.createContext();

export default function App() {
  return (
    <UserContext.Provider value="Reed">
      <User />
    </UserContext.Provider>
  )
}

function User() {
  return (
    <UserContext.Consumer>
      {value => <h1>{value}</h1>} 
      {/* stampa: Reed */}
    </UserContext.Consumer>
  )
}

Analizziamo passo dopo passo quello che stiamo facendo:

  1. Al di sopra del componente App creiamo il contesto con React.createContext() e lo assegniamo a una variabile, UserContext. In quasi tutti i casi, vorrai esportarlo nel modo in cui lo stiamo facendo qui, in quanto i tuoi componenti si troveranno in un altro file. Nota che possiamo passare un valore iniziale alla prop value quando chiamiamo React.createContext().
  2. Nel componente App usiamo UserContext. In particolare UserContext.Provider. Il contesto creato è un oggetto con due proprietà: Provider (fornitore) e Consumer (consumatore), entrambi i quali sono componenti. Per passare il nostro valore a ogni componente nella nostra app, dobbiamo racchiudere all'interno del componente Provider il componente (o i componenti) che deve utilizzare il contesto (in questo caso User).
  3. In UserContext.Provider, inseriamo il valore che vogliamo passare a tutta la nostra alberatura di componenti. Per farlo lo assegniamo alla prop value. In questo caso il nostro nome (il mio è Reed).
  4. In User, o qualunque componente che vogliamo utilizzi quello che viene fornito nel nostro contesto, utilizziamo il componente UserContext.Consumer. Per passare il valore usiamo quello che è noto come modello di presentazione delle prop (render props pattern). È semplicemente una funzione che il componente consumer ci fornisce come prop. Come valore di ritorno di quella funzione, possiamo restituire e usare value.

Cos'è l'hook useContext?

Se esaminiamo l'esempio qui sopra, il modello di presentazione delle prop per l'utilizzo del contesto ti potrebbe sembrare un po' strano.

Un altro modo di utilizzare il contesto è disponibile in React dalla versione 16.8 con l'arrivo degli hook di React. Ora possiamo usare il contesto con l'hook useContext .

Invece di usare il modello di presentazione delle prop possiamo passare l'intero oggetto contesto a React.useContext() per utilizzarlo all'inizio del nostro componente.

Ecco l'esempio di cui sopra usando l'hook useContext:

import React from 'react';

export const UserContext = React.createContext();

export default function App() {
  return (
    <UserContext.Provider value="Reed">
      <User />
    </UserContext.Provider>
  )
}

function User() {
  const value = React.useContext(UserContext);  
    
  return <h1>{value}</h1>;
}

Il vantaggio dell'hook useContext è che rende il nostro componente più conciso e ci consente di creare i nostri hook personalizzati.

Puoi usare il componente consumer direttamente oppure usare l'hook useContext, a seconda del modello che preferisci.

Potrebbe non servirti il contesto

L'errore che molti sviluppatori commettono è usare il contesto quando devono solo passare prop attraverso diversi livelli per raggiungere un componente.

Ecco un'applicazione con un componente Avatar annidato a cui servono due prop, username e avatarSrc dal componente App .

export default function App({ user }) {
  const { username, avatarSrc } = user;

  return (
    <main>
      <Navbar username={username} avatarSrc={avatarSrc} />
    </main>
  );
}

function Navbar({ username, avatarSrc }) {
  return (
    <nav>
      <Avatar username={username} avatarSrc={avatarSrc} />
    </nav>
  );
}

function Avatar({ username, avatarSrc }) {
  return <img src={avatarSrc} alt={username} />;
}

Se possibile, vorremmo evitare di passare prop multiple attraverso componenti a cui non servono.

Come possiamo fare?

Invece di ripiegare immediatamente sul contesto, in quanto stiamo facendo prop drilling, dovremmo costruire meglio i nostri componenti.

Visto che solo il componente di livello più alto, App, deve sapere che esiste un componente Avatar, possiamo crearlo direttamente all'interno di App.

Questo ci consente di passare una singola prop, avatar, invece di due.

export default function App({ user }) {
  const { username, avatarSrc } = user;

  const avatar = <img src={avatarSrc} alt={username} />;

  return (
    <main>
      <Navbar avatar={avatar} />
    </main>
  );
}

function Navbar({ avatar }) {
  return <nav>{avatar}</nav>;
}

In breve: non considerare subito il contesto. Vedi se puoi organizzare meglio i tuoi componenti per evitare il prop drilling.

Il contesto di React sostituisce Redux?

Sì e no.

Per molti principianti di React, Redux è un modo per passare dati molto più facilmente. Questo perché Redux stesso è dotato di un contesto React.

Tuttavia, se non stai anche aggiornando lo stato, ma passi semplicemente i dati attraverso la tua alberatura di componenti, non ti serve una libreria di gestione dello stato come Redux.

Avvertenze sul contesto di React

Come mai non è possibile aggiornare il valore che il contesto di React mette a disposizione?

Sebbene sia possibile combinare il contesto di React con un hook come useReducer e creare una libreria di gestione dello stato improvvisata senza ricorrere a librerie di terze parti, in genere non è consigliato per ragioni di prestazione.

Il problema con questo approccio è dato dal fatto che il contesto di React fa scattare una ripresentazione (re-rendering) dei componente.

Se stai passando un oggetto sul tuo fornitore di contesto React e una qualunque proprietà in esso si aggiorna, cosa succede? Qualsiasi componente che utilizzi quel contesto verrà ripresentato.

Questo potrebbe non costituire un problema di prestazioni in piccole applicazioni con pochi valori di stato che non sono aggiornati molto spesso (tipo i dati di un tema). Il problema sorge se esegui molti aggiornamenti di stato in un'applicazione con molti componenti nella tua alberatura.

Conclusione

Spero che questa guida ti abbia dato una migliore comprensione di come utilizzare il contesto di React in ogni suo aspetto.

Se approfondire ulteriormente l'utilizzo del contesto di React per creare fantastici progetti React, dai un'occhiata a The React Bootcamp (risorsa in inglese).