Vai al contenuto principale

Come si fa il fetch dei dati in React?

Esplora le tecniche avanzate di fetching dati in React: dalla Fetch API e useEffect a SWR per esperienze utente fluide e performanti.

Nell'ambito dello sviluppo web contemporaneo, l'efficienza e la dinamicità nel recupero dei dati sono essenziali per garantire esperienze utente fluide e immediate. React, che si distingue tra le librerie JavaScript per la realizzazione di interfacce utente, mette a disposizione una varietà di strumenti e modelli progettuali specificamente ideati per agevolare il fetching dei dati.

In questo contesto, voglio esplorare le principali metodologie impiegate nel fetching dei dati all'interno di applicazioni React. Saranno illustrati l'utilizzo della Fetch API per effettuare richieste HTTP, l'impiego dell'hook useEffect per la gestione di effetti collaterali, le strategie di gestione degli stati utili a monitorare le fasi di caricamento, l'eventuale presenza di errori e la ricezione dei dati, fino all'introduzione di SWR come avanzata tecnica di fetching dati, che promette di ottimizzare ulteriormente queste operazioni.

Fetch API e useEffect

Il punto di partenza per il fetching dei dati in un'applicazione React è la Fetch API del browser, che permette di effettuare richieste HTTP asincrone in JavaScript. Combinata con l'hook useEffect di React, che consente di eseguire effetti collaterali in componenti funzionali, possiamo facilmente orchestrare il fetching dei dati all'avvio del componente o in risposta a cambiamenti di stato o prop.

La Fetch API fornisce un'interfaccia JavaScript per l'accesso e la manipolazione di parti della pipeline HTTP, come le richieste e le risposte. Questa API offre una definizione più potente e flessibile per le operazioni di rete. Rispetto a XMLHttpRequest, è più semplice e più potente. Ne ho già parlato ampiamente durante il corso di JavaScript.

Per eseguire una chiamata HTTP utilizzando la Fetch API, si può utilizzare il metodo fetch(), che accetta il primo parametro come URL della risorsa che si desidera recuperare e un oggetto opzionale di opzioni per personalizzare la richiesta HTTP. Ritorna una promessa che risolve in un oggetto Response. Come si fa però ad usare fetch con React?

Uso di useEffect per il fetching dei dati

useEffect è un hook che permette di eseguire effetti collaterali in componenti funzionali. È comunemente usato per il fetching di dati, sottoscrizioni, o manualmente cambiare il DOM in React components. Lo abbiamo già incontrato nella lezione sugli hook.

Quando si utilizza useEffect per il fetching di dati, si colloca la chiamata alla Fetch API all'interno della funzione passata a useEffect. Ciò assicura che la chiamata alla Fetch API venga eseguita dopo che il componente è stato montato. Per evitare chiamate API ripetute o infinite, è importante includere un array di dipendenze vuoto come secondo argomento di useEffect, indicando che l'effetto non dipende da alcuna prop o stato e quindi dovrebbe eseguire solo una volta.

In questo esempio, utilizzeremo la Fetch API per recuperare i dati da un'API fittizia e li visualizzeremo in un componente. Questo esempio si concentrerà sull'uso di useEffect per effettuare il fetch dei dati al caricamento del componente e sull'uso delle interfacce TypeScript per definire il tipo di dati atteso dalla risposta.

Per semplificare, non gestiremo gli stati di caricamento o errore, ma ti mostrerò come potresti fare per estendere l'esempio.

Definiamo prima l'interfaccia per i dati che ci aspettiamo di ricevere:

import React from 'react';

interface Todo {
  userId: number,
  id: number,
  title: string,
  completed: boolean
}

const TodoList: React.FC = () => {
  const [todos, setTodos] = React.useState<Todo[]>([]);

  React.useEffect(() => {
    const fetchData = async() => {
      const response = await fetch('https://jsonplaceholder.typicode.com/todos');
      const data = await response.json();
      setTodos(data);
    };
    fetchData().catch(console.error);
  }, []);

  return (
    <div>
      <h1>Todo List</h1>
      <ul>
        {todos.map(todo => (
          <li key={todo.id} style={{textDecoration: todo.completed ? 'line-through' : 'none'}}>
            {todo.title}
          </li>
        ))}
      </ul>
    </div>
  );
}

export default TodoList;

In questo esempio:

  • Abbiamo definito un'interfaccia Todo per descrivere la struttura dei dati del todo che ci aspettiamo di ricevere dall'API.
  • Abbiamo creato un componente TodoList che:
    • Utilizza lo stato todos per memorizzare l'elenco degli utenti recuperati.
    • Utilizza l'hook useEffect per effettuare il fetch dei dati quando il componente viene montato. L'array di dipendenze vuoto ([]) assicura che l'effetto venga eseguito solo una volta dopo il primo rendering.
    • Definisce una funzione asincrona fetchData all'interno dell'hook useEffect, che effettua il fetch dei dati e aggiorna lo stato todos con i dati ricevuti.
    • Visualizza l'elenco dei todo utilizzando il metodo map per iterare su ogni elemento dell'array todos e restituire un elemento della lista per ciascun utente.

Così però è poco user friendly, possiamo migliorare l’esempio con la gestione degli stati di caricamento.

Gestione degli Stati

La gestione degli stati di caricamento, errore e dati è cruciale per informare l'utente sullo stato della richiesta di dati. Utilizzando gli hook di stato di React, come useState, possiamo tracciare queste condizioni e rendere la nostra UI reattiva a cambiamenti nel ciclo di vita del fetching dei dati.

Aggiungiamo alla nostra implementazione precedente la gestione degli stati di caricamento per fornire feedback visivo all'utente durante il recupero dei dati. Questo è particolarmente utile in ambienti reali dove le risposte dell'API possono richiedere un po' di tempo.

Per gestire lo stato di caricamento, aggiungeremo due nuovi stati isLoading e error che ci permetterà di sapere quando i dati stanno venendo caricati, quando il caricamento è completato o se ci sono stati degli errori. Vediamo come si modifica l'esempio:

import React, { useEffect, useState } from 'react';

interface Todo {
  userId: number,
  id: number,
  title: string,
  completed: boolean
}

const TodoList: React.FC = () => {
  const [todos, setTodos] = useState<Todo[]>( [] );
  const [isLoading, setIsLoading] = useState<boolean>( true );
  const [error, setError] = useState<string | null>( null );

  useEffect( () => {
    const fetchData = async () => {
      setIsLoading( true );
      setError( null );
      try {
        const response = await fetch( 'https://jsonplaceholder.typicode.com/todos' );
        if ( !response.ok ) {
          throw new Error( 'Network response was not ok' );
        }
        const data = await response.json();
        setTodos( data );
      } catch ( error: any ) {
        setError( error.message || 'Errore sconosciuto' );
      } finally {
        setIsLoading( false );
      }
    };
    fetchData();
  }, [] );

  return (
    <div>
      <h1>Todo List</h1>
      {isLoading ? (
        <p>Loading...</p>
      ) : error ? (
        <p>Error: {error}</p>
      ) : (
        <ul>
          {todos.map( ( todo ) => (
            <li key={todo.id} style={{ textDecoration: todo.completed ? 'line-through' : 'none' }} >
              {todo.title}
            </li>
          ) )}
        </ul>
      )}
    </div>
  );
}

export default TodoList;

Questo approccio migliora l'esperienza utente indicando chiaramente quando i dati sono in fase di caricamento e gestendo in modo elegante sia il successo che il fallimento del fetch dei dati.

Nell'esempio sopra, abbiamo introdotto tre stati utilizzando lo useState hook: todos, loading, e error. Questi stati aiutano a gestire le diverse fasi del ciclo di vita di una richiesta HTTP in un componente React:

  • Caricamento (loading): Inizialmente impostato su true, questo stato indica che la richiesta è in corso. Puoi utilizzarlo per mostrare un indicatore di caricamento all'utente.
  • Errore (error): Se la richiesta fallisce per qualsiasi motivo (ad esempio, problemi di rete, risposte errate dal server), questo stato viene utilizzato per catturare e mostrare un messaggio di errore.
  • Todos (todos): Una volta che la richiesta ha successo, i dati recuperati vengono salvati in questo stato. Puoi poi utilizzarlo per visualizzare i dati all'interno del tuo componente.

Questo approccio consente di creare un'esperienza utente fluida e informativa durante l'interazione con le API web in un'applicazione React.

SWR: Stale While Revalidate

Per un approccio più sofisticato al fetching dei dati, introduciamo SWR, una libreria per React che implementa il pattern "stale-while-revalidate".

SWR fornisce una soluzione elegante per il caching dei dati, la riconvalida in background, e molte altre funzionalità avanzate che aiutano a migliorare le prestazioni e l'esperienza utente delle applicazioni web. Grazie alla sua API semplice ma potente, SWR semplifica il processo di fetching dei dati, riducendo la complessità e il codice boilerplate.

SWR è una libreria creata dal team di Vercel che si basa sull'idea di "stale-while-revalidate" (vecchio mentre convalida), un approccio HTTP caching che permette di mostrare prima i dati cache (stale), poi di fare il fetch dei dati aggiornati (revalidate), e infine di aggiornare l'interfaccia con i dati freschi. SWR fornisce una serie di funzionalità per migliorare l'esperienza di fetching dei dati nelle applicazioni web, come caching automatico, re-fetching in background, e molto altro.

Caratteristiche principali di SWR:

  • Data Fetching senza configurazione: SWR gestisce automaticamente il caching, la convalida in background, e il mantenimento dello stato, riducendo la necessità di codice boilerplate.
  • Re-fetching intelligente: SWR re-fetcha i dati automaticamente quando l'utente riporta in primo piano l'app, quando si recupera la connessione di rete, o a intervalli di tempo configurabili.
  • UI sempre reattiva: Grazie al suo sistema di caching e aggiornamento, SWR permette di avere un'interfaccia utente che rimane reattiva e veloce, mostrando dati immediatamente e aggiornandoli in background.
  • Semplice ma potente API: SWR offre un'API semplice da usare, ma estremamente configurabile e estensibile per adattarsi a casi d'uso avanzati.

Esempio di utilizzo di SWR:

Per iniziare con SWR, prima è necessario installare la libreria:

npm install swr

Ecco un esempio di come si può utilizzare SWR per fetchare i dati di un utente da un'API:

import React from 'react';
import useSWR from 'swr';

interface Todo {
  userId: number,
  id: number,
  title: string,
  completed: boolean
}

const fetcher = ( url: string ) => fetch( url ).then( ( res ) => res.json() );

const TodoList: React.FC = () => {
  const { data: todos, error } = useSWR<Todo[]>( 'https://jsonplaceholder.typicode.com/todos', fetcher );

  if ( error ) return <div>Failed to load</div>;
  if ( !todos ) return <div>Loading...</div>;
  return (
    <ul>
      { todos.map( ( todo ) => (
        <li key={ todo.id } style={ { textDecoration: todo.completed ? 'line-through' : 'none' } }>
          { todo.title }
        </li>
      ) ) }
    </ul>
  )
}

export default TodoList;

Nell'esempio, useSWR accetta due parametri: la chiave di cache (in questo caso, l'URL dell'API) e una funzione fetcher che definisce come recuperare i dati (in questo esempio, usando la Fetch API standard per ottenere i dati in formato JSON). SWR utilizza la chiave di cache per de-duplicare le richieste e condividere i dati tra componenti, ottimizzando le performance e riducendo il carico sul server.

Qualche informazioni in più su SWR

  • Gestione degli errori: SWR fornisce un modo semplice per gestire gli errori attraverso lo stato error restituito dal hook useSWR.
  • Convalida iniziale e di background: SWR esegue automaticamente la convalida dei dati all'avvio dell'applicazione e in background per mantenere i dati aggiornati senza interrompere l'esperienza dell'utente.
  • Configurazioni globali e locali: SWR consente di definire configurazioni sia a livello globale che locale, permettendo di personalizzare il comportamento del fetching in base alle necessità specifiche del componente o dell'applicazione.
  • Plugin e middleware: SWR supporta plugin e middleware che estendono le sue funzionalità, come la possibilità di aggiungere funzionalità di retry automatico o integrazioni con altre librerie di gestione dello stato.

SWR rappresenta una soluzione moderna e efficiente per la gestione del fetching dei dati nelle applicazioni React, offrendo un approccio ottimizzato e basato sulle performance senza sacrificare la flessibilità o la potenza.

Unisciti a WebTea

Niente spam. Solo contenuti formativi su Software Engineering.

Ci sono due cose che non ci piacciono: lo spam e il mancato rispetto della privacy. Seleziona come vuoi restare in contatto:

Preferenze di contatto

Usiamo Mailchimp come piattaforma di marketing. Cliccando su iscriviti, accetti la nostra privacy policy e che le tue informazioni vengano trasferite a Mailchimp per l'elaborazione. Termini e Privacy. Puoi disiscriverti in qualsiasi momento.