Frontend

Come usare le context API in React

Autore

Manuel Ricci

Le Context API in React rappresentano un meccanismo efficace per il "prop drilling", ovvero la pratica di passare i dati da un componente all'altro attraverso le props, anche quando ciò non è strettamente necessario. Invece di passare i props a tutti i livelli dell'applicazione, le Context API permettono di condividere valori direttamente tra i componenti, senza doverli passare esplicitamente attraverso ogni livello dell'albero dei componenti. Questo rende molto più semplice la gestione dello stato globale dell'applicazione, specialmente in progetti di grandi dimensioni.

Come Funzionano le Context API

Le Context API funzionano creando un "contexto", che è un modo per condividere i valori tra i componenti senza dover utilizzare le props. Un contesto può essere definito utilizzando React.createContext(), e ha due parti principali: il Provider e il Consumer.

  • Provider: Un componente che fornisce il valore del contesto ai suoi componenti figli. Tutti i componenti figli, indipendentemente da quanto profondamente sono annidati, possono accedere a questo valore senza doverlo ricevere esplicitamente come prop.
  • Consumer: Un componente che consuma il valore fornito dal Provider. In alternativa, si può utilizzare l'hook useContext per accedere al valore del contesto in componenti funzionali.

Gestione dello stato complessa

Quando si ha a che fare con una logica di stato più complessa, combinare useContext con useReducer in React può offrire un approccio più strutturato e scalabile. Questo metodo è particolarmente utile per gestire stati globali che richiedono diverse azioni per essere aggiornati in maniera prevedibile.

Gestione dello Stato di Autenticazione

In questo esempio, creeremo un contesto di autenticazione per un'applicazione, utilizzando useContext per accedere allo stato e alle azioni di autenticazione, e useReducer per gestire le modifiche allo stato.

Definizione del Reducer e del Contexto

Primo, definiamo il reducer e il contesto. Creeremo un file AuthContext.tsx.

1import React, { createContext, useContext, useReducer, ReactNode } from 'react';
2
3type AuthState = {
4  isAuthenticated: boolean;
5};
6
7type AuthAction =
8  | { type: 'LOGIN' }
9  | { type: 'LOGOUT' };
10
11const initialState: AuthState = {
12  isAuthenticated: false,
13};
14
15const AuthContext = createContext<{ state: AuthState; dispatch: React.Dispatch<AuthAction> } | undefined>(undefined);
16
17function authReducer(state: AuthState, action: AuthAction): AuthState {
18  switch (action.type) {
19    case 'LOGIN':
20      return { ...state, isAuthenticated: true };
21    case 'LOGOUT':
22      return { ...state, isAuthenticated: false };
23    default:
24      return state;
25  }
26}
27
28export const AuthProvider = ({ children }: { children: ReactNode }) => {
29  const [state, dispatch] = useReducer(authReducer, initialState);
30
31  return (
32    <AuthContext.Provider value={{ state, dispatch }}>
33      {children}
34    </AuthContext.Provider>
35  );
36};
37
38export const useAuth = () => {
39  const context = useContext(AuthContext);
40  if (!context) {
41    throw new Error('useAuth must be used within an AuthProvider');
42  }
43  return context;
44};

Qui, AuthContext è il contesto che abbiamo creato, che conterrà lo stato di autenticazione e una funzione dispatch per eseguire azioni. AuthProvider è il componente che useremo per avvolgere la parte dell'applicazione che ha bisogno di accedere a queste informazioni. useAuth è un hook personalizzato che facilita l'accesso al contesto di autenticazione.

Utilizzo del Contexto di Autenticazione

Per utilizzare il contesto, avvolgiamo i nostri componenti con AuthProvider nel punto più alto possibile dell'albero dei componenti, tipicamente in App.tsx.

1import React from 'react';
2import { AuthProvider } from './AuthContext';
3import LoginComponent from './LoginComponent';
4
5function App() {
6  return (
7    <AuthProvider>
8      <LoginComponent />
9    </AuthProvider>
10  );
11}
12
13export default App;

E infine, un componente che utilizza useAuth per effettuare il login e il logout:

1import React from 'react';
2import { useAuth } from './AuthContext';
3
4const LoginComponent = () => {
5  const { state, dispatch } = useAuth();
6
7  return (
8    <div>
9      {state.isAuthenticated ? (
10        <>
11          <p>Sei autenticato!</p>
12          <button onClick={() => dispatch({ type: 'LOGOUT' })}>Logout</button>
13        </>
14      ) : (
15        <>
16          <p>Non sei autenticato.</p>
17          <button onClick={() => dispatch({ type: 'LOGIN' })}>Login</button>
18        </>
19      )}
20    </div>
21  );
22};
23
24export default LoginComponent;

In questo componente, usiamo useAuth per accedere allo stato di autenticazione e alla funzione dispatch. I pulsanti permettono all'utente di effettuare il login o il logout, triggerando un cambiamento nello stato globale di autenticazione che si riflette in tutta l'applicazione.

Conclusione

L'uso combinato di useContext e useReducer fornisce un potente strumento per gestire lo stato complesso in modo più prevedibile e organizzato. Questo pattern è particolarmente utile per gestire stati globali in applicazioni grandi e complesse, offrendo una chiara separazione tra la logica di gestione dello stato e l'interfaccia utente.

Caricamento...

Diventiamo amici di penna? ✒️

Iscriviti alla newsletter per ricevere una mail ogni paio di settimane con le ultime novità, gli ultimi approfondimenti e gli ultimi corsi gratuiti puubblicati. Ogni tanto potrei scrivere qualcosa di commerciale, ma solo se mi autorizzi, altrimenti non ti disturberò oltre.

Se non ti piace la newsletter ti ricordo la community su Discord, dove puoi chiedere aiuto, fare domande e condividere le tue esperienze (ma soprattutto scambiare due meme con me). Ti aspetto!

Ho in previsione di mandarti una newsletter ogni due settimane e una commerciale quando capita.