CONTATTACI

Guide per aspiranti programmatori

Programmatore che esamina react al microscopio
Lezione 37 / 41

Quando evitare l’uso di Context in React

Quando si parla di Context, c’è un classico caso d’uso problematico che andrebbe evitato: vediamo quale e perché.

Normalmente, l’utilizzo di Context si divide in tre passi:

 

  1. La chiamata a createContext.
  2. La creazione del Provider.
  3. Le chiamate a useContext.

 

Due classici errori che si fanno quando si utilizza Context sono:

 

  1. Non passare un valore di default a createContext.
  2. Esportare l’istanza di Context.

 

Per esempio, viene creata l’istanza di Context in un file (senza valore di default):

 

import { createContext } from "react";

export const AuthContext = createContext();

E, poi, viene importata in un file separato per l’utilizzo del Provider:

 

import { AuthContext } from "./AuthContext";

export default function AuthContextProvider({ children }) {
  // ...

  return (
    <AuthContext.Provider
      value={
        {
          /* ... */
        }
      }
    >
      {children}
    </AuthContext.Provider>
  );
}

Infine, vengono utilizzati Context e Provider importati dai due file diversi:

 

import { AuthContext } from "../contexts/AuthContext";
import { AuthContextProvider } from "../contexts/AuthContextProvider";

export default function SomeComponent() {
  const { isLoggedIn, login, logout } = useContext(AuthContext);

  return <AuthContextProvider>{/* ... */}</AuthContextProvider>;
}

Questi due errori portano a due problemi:

 

  1. L’assenza di un valore predefinito passato createContext rende più difficile a chi vorrebbe usarlo capire che tipo di funzionalità sono previste. Se il Provider, poi, è definito in un file separato, la ricerca diventa ancora più frustrante.
  2. Esportare l’istanza di Context significa renderlo disponibile non solo per l’utilizzo da Consumer, ma anche per l’utilizzo da Provider. Chiunque potrebbe creare un secondo AuthContextProvider o, peggio ancora, utilizzare direttamente AuthContext.Provider in un componente, generando il caos.

 

Ecco perché non abbiamo esportato AuthContext. Non avendolo esportato, è impossibile utilizzare questa sintassi in un componente:

 

const { isLoggedIn, login, logout } = useContext(AuthContext);
//                                               ^^^^^^^^^^^
//                                             irraggiungibile!
Ecco perché esportiamo una funzione hook apposita, useAuthContext:
export function useAuthContext() {
  return useContext(AuthContext);
}

Come ormai sai bene, le funzioni hook sono funzioni che hanno un nome che inizia per use e possono usare altre funzioni hook. useAuthContext ha un nome che inizia per use e, di conseguenza, può utilizzare la funzione hook useContext fornita da React.

A questo punto, non ci resta che fare due cose:

 

  1. Inserire il componente AuthContextProvider.
  2. Utilizzare useAuthContext.

 

Useremo useAuthContext in App, perché è lì che gestiamo l’autenticazione. Di conseguenza, AuthContextProvider dovrà essere un componente genitore di App, perché possiamo usare un Context solo se il componente che lo usa è figlio del Provider di quel Context. L’unico punto in cui possiamo inserire componenti genitori di App è index.js (o index.jsx, se hai usato Vite).

 

// File: src/index.js(x)

// ...

import { AuthContextProvider } from "./contexts/AuthContext";

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  <React.StrictMode>
    <AuthContextProvider>
      <App />
    </AuthContextProvider>
  </React.StrictMode>
);

// ...

Ora possiamo usare useAuthContext in App:

 

// File: src/App.jsx

// ...

import { useAuthContext } from "./contexts/AuthContext";

// ...

export default function App() {
  const { isLoggedIn, login } = useAuthContext();

  // ...

  if (isLoggedIn()) {
    return <div className="App">{/* ... */}</div>;
  } else {
    return <LoginForm onLogin={login} />;
  }
}

Ora, se volessimo inserire un bottone “Logout” in un componente, ci basterebbe scrivere una cosa del genere:

 

export default function AnyComponent() {
  const { logout } = useAuthContext();

  return (
    {/* ... */}
    <button onClick={logout}>Logout</button>
    {/* ... */}
  )
}

Il fatto di non aver esportato AuthContext ci permette di legarlo al concetto di autenticazione dell’utente, esponendo solo le funzionalità che servono. Come nel caso delle funzioni hook, Context è un modo per isolare funzionalità e concetti. AuthContext gestisce internamente il flusso di autenticazione attraverso una macchina a stati finiti ed espone la possibilità di leggerne lo stato e scatenarne le transizioni.

 

I pericoli dell’uso di Context in React

L’utilizzo di Context, come abbiamo visto, è estremamente comodo per evitare il problema del prop drilling. Come sempre, però, essendo una cosa che esula dal normale comportamento di React (prop, eventi e stati) è uno strumento da usare con moderazione.

Un utilizzo eccessivo di Context – per esempio usandolo anche solo per evitare il passaggio di prop da un componente al foglio del figlio – potrebbe portare a questi problemi:

 

  1. Eccessiva frammentazione della logica: Context andrebbe usato per isolare concetti indipendenti, come l’autenticazione dell’utente, il tema grafico dell’applicazione o una configurazione globale. Usarlo solo come strumento per evitare il prop drilling potrebbe distrarti dal suo vero scopo e portarti a creare Context legati a pezzi di stato dell’applicazione, come una pagina specifica, un form, una chiamata di rete.
  2. Diminuzione della riusabilità dei componenti: i Provider sono dei componenti controller che controllano componenti view su più livelli, condividendone lo stato. Questo significa che ogni componente Consumer, oltre a essere legato alle prop, è legato anche al Provider. Se volessimo spostare un componente del genere da un’applicazione a un’altra, oltre a collegarne le prop, dovremmo anche ricreare le istanze Context corrispondenti, oppure modificare il componente per smettere di utilizzare le istanze di Context.
  3. Problemi di Performance: sappiamo che, ogni volta che un componente cambia stato, React chiama tutti i suoi discendenti al rendering. I Provider sono normalmente utilizzati a un livello molto vicino alla radice dell’applicazione (il nostro componente App) o, come nel nostro caso, a un livello ancora più estero (index.js(x)). Di conseguenza, il cambio dello stato di un’istanza di Context scatena normalmente grandi cicli di rendering, mettendo a dura prova le performance di React.

 

Occhio, quindi, a non esagerare!

Contattaci senza impegno per informazioni sul corso

Pagamento rateale

Valore della rata: A PARTIRE DA 115 €/mese.

Esempio di finanziamento 

Importo finanziato: € 2440 in 24 rate da € 115 – TAN fisso 9,55% TAEG 12,57% – importo totale del credito € 2841.

Il costo totale del credito comprende: interessi calcolati al TAN indicato, oneri fiscali (imposta di bollo sul contratto 16,00 euro*) addebitati sulla prima rata, costo mensile di gestione pratica € 3,90, spesa di istruttoria € 0,00, spesa per invio rendicontazione periodica cartacea € 0,98 (o spesa per invio rendicontazione periodica cartacea € 0,00), imposta di bollo su rendicontazione periodica € 0,00. Modalità di rimborso obbligatoria: addebito diretto su c/c. La scadenza delle rate è determinata dal giorno della liquidazione del contratto; la data di scadenza delle rate è prevista il giorno 15 del mese. L’importo di ciascuna rata comprende una quota di capitale crescente e interessi decrescente secondo un piano di ammortamento “alla francese”. Offerta valida dal 01/01/2024 al 31/12/2024.

Messaggio pubblicitario con finalità promozionale. Per le informazioni precontrattuali richiedere sul punto vendita il documento “Informazioni europee di base sul credito ai consumatori” (SECCI) e copia del testo contrattuale. Salvo approvazione di Sella Personal Credit S.p.A. Aulab S.r.l. opera quale intermediario del credito NON in esclusiva.

*In fase di richiesta del finanziamento verrà proposta la facoltà di selezionare, in alternativa all’imposta di bollo sul contratto di 16,00 euro, l’imposta sostitutiva, pari allo 0,25% dell’importo finanziato.

Pagamento rateale

Valore della rata: A PARTIRE DA 210 €/mese.

Esempio di finanziamento  

Importo finanziato: € 4500 in 24 rate da € 210,03 – TAN fisso 9,68% TAEG 11,97% – importo totale del credito € 5146,55.

Il costo totale del credito comprende: interessi calcolati al TAN indicato, oneri fiscali (imposta di bollo sul contratto 16,00 euro*) addebitati sulla prima rata, costo mensile di gestione pratica € 3,90, spesa di istruttoria € 0,00, spesa per invio rendicontazione periodica cartacea € 0,98 (o spesa per invio rendicontazione periodica cartacea € 0,00), imposta di bollo su rendicontazione periodica € 0,00. Modalità di rimborso obbligatoria: addebito diretto su c/c. La scadenza delle rate è determinata dal giorno della liquidazione del contratto; la data di scadenza delle rate è prevista il giorno 15 del mese. L’importo di ciascuna rata comprende una quota di capitale crescente e interessi decrescente secondo un piano di ammortamento “alla francese”. Offerta valida dal 01/01/2024 al 31/12/2024.

Messaggio pubblicitario con finalità promozionale. Per le informazioni precontrattuali richiedere sul punto vendita il documento “Informazioni europee di base sul credito ai consumatori” (SECCI) e copia del testo contrattuale. Salvo approvazione di Sella Personal Credit S.p.A. Aulab S.r.l. opera quale intermediario del credito NON in esclusiva.

* In fase di richiesta del finanziamento verrà proposta la facoltà di selezionare, in alternativa all’imposta di bollo sul contratto di 16,00 euro, l’imposta sostitutiva, pari allo 0,25% dell’importo finanziato.

Contattaci senza impegno per informazioni sul corso

Scopriamo insieme se i nostri corsi fanno per te. Compila il form e aspetta la chiamata di uno dei nostri consulenti.