CONTATTACI

Guide per aspiranti programmatori

Programmatore che esamina react al microscopio
Lezione 26 / 41

Esempi di hooks: richieste di rete di tipo comando

Nelle sezioni precedenti, abbiamo gestito in modo dichiarativo la richiesta di rete per creare un elemento della lista di cose da fare:

 

// File: src/components/TodoItemForm.jsx

// ...

const NetworkRequestType = {
  idle: "idle",
  loading: "loading",
  success: "success",
  failure: "failure",
};

function makeIdleNetworkRequest() {
  return { type: NetworkRequestType.idle };
}

function makeLoadingNetworkRequest() {
  return { type: NetworkRequestType.loading };
}

function makeSuccessfulNetworkRequest(response) {
  return { type: NetworkRequestType.success, response };
}

function makeFailedNetworkRequest(error) {
  return { type: NetworkRequestType.failure, error };
}

export default function TodoItemForm({ onSubmit }) {
  // ...
  const [networkState, setNetworkState] = useState(makeIdleNetworkRequest());

  // ...
  const onFormSubmit = (event) => {
    event.preventDefault();
    setNetworkState(makeLoadingNetworkRequest());

    createTodoItem(todoItem).then(
      (todoItem) => {
        setNetworkState(makeSuccessfulNetworkRequest(todoItem));
        onSubmit(todoItem);
        setTodoItem({ description: "", isDone: false });
      },
      (error) => {
        setNetworkState(makeFailedNetworkRequest(error.message));
      }
    );
  };

  // ...
}

Questo tipo di funzionamento non vale solo per la richiesta di rete che crea l’elemento della lista di cose da fare, ma per tutte le richieste di rete di tipo “comando”, cioè quelle richieste che partono all’occorrenza, come al click di un bottone (a differenza, per esempio, di una richiesta per ottenere gli elementi già esistenti, che partirebbe nel momento in cui viene visualizzata la pagina).

Il concetto di richiesta di rete di tipo “comando” è un ottimo argomento per una funzione hook. Possiamo creare una funzione hook, che potremmo chiamare useCommand. – ricordiamoci che le funzioni hook sono funzioni che hanno un nome che inizia per use e che possono, al loro interno, fare uso di altre funzioni hook, come useState – .

Avendo a che fare con una funzione, dobbiamo prima di tutto decidere quali sono gli argomenti che riceve (il suo input) e qual è il risultato che restituisce (il suo output).

Per quanto riguarda l’output, ci servono sicuramente lo stato della richiesta di rete (idle, loading, success o failure) e una funzione da chiamare per far partire la richiesta, per esempio al click del bottone che dice “submit”.

La funzione per far partire la richiesta prenderà come argomenti i dati dell’elemento della lista, che abbiamo a disposizione in un momento del tempo diverso. Come nell’esempio dei validatori del form, ci sono alcuni dati che abbiamo a disposizione nel momento in cui scriviamo il codice, come l’URL a cui inviare la richiesta o il metodo HTTP che vogliamo usare. Altri dati invece – come la descrizione dell’elemento – li avremo a disposizione nel momento in cui l’utente li inserirà nel form.

Non avendo a disposizione un back-end, modifichiamo la funzione che finge di inviare una richiesta di rete per accettare un percorso e un metodo HTTP, come se fosse la funzione fetch del browser:

 

// File: src/mock/sendNetworkRequest.js
export function sendNetworkRequest({ path, method, data, shouldFail = false }) {
  console.log(`Would send a ${method} request to ${path}`);

  return new Promise((resolve, reject) => {
    window.setTimeout(() => {
      if (shouldFail) {
        reject(new Error("Filed!"));
      } else {
        resolve(data);
      }
    }, 1000);
  });
}

In un caso realistico, l’URL del server a cui inviamo la richiesta sarebbe salvato in un file env, che conterrebbe le variabili d’ambiente. La funzione per inviare le richieste accetterebbe come argomento, come nel nostro caso, il percorso (path) per completare l’URL. Ad esempio, la variabile d’ambiente potrebbe contenere il valore https://my-api.com e il path potrebbe essere /todo, così che la richiesta venga inviata a https://my-api.com/todo.

Per informazioni dettagliate sulle variabili d’ambiente in React, puoi fare riferimento alla guida ufficiale.

Ora che possiamo fingere di mandare una richiesta di rete, dividiamo in due fasi l’invio perché, come abbiamo detto, path e method sono disponibili sempre, mentre data sarà disponibile in futuro. Creiamo una nuova cartella hooks per raccogliere le nostre funzioni hook, in cui possiamo creare un nuovo file useCommand.js:

 

// File: src/hooks/useCommand.js

import { useState } from "react";
import { sendNetworkRequest } from "../mock/sendNetworkRequest";

export const NetworkRequestType = {
  idle: "idle",
  loading: "loading",
  success: "success",
  failure: "failure",
};

function makeIdleNetworkRequest() {
  return { type: NetworkRequestType.idle };
}

function makeLoadingNetworkRequest() {
  return { type: NetworkRequestType.loading };
}

function makeSuccessfulNetworkRequest(response) {
  return { type: NetworkRequestType.success, response };
}

function makeFailedNetworkRequest(error) {
  return { type: NetworkRequestType.failure, error };
}

export function useCommand({ path, method }) {
  const [networkRequest, setNetworkRequest] = useState(
    makeIdleNetworkRequest()
  );

  const sendCommand = (data) => {
    setNetworkRequest(makeLoadingNetworkRequest());

    return sendNetworkRequest({ path, method, data }).then(
      (response) => {
        setNetworkRequest(makeSuccessfulNetworkRequest(response));
        return Promise.resolve(response);
      },
      (error) => {
        setNetworkRequest(makeFailedNetworkRequest(error));
        return Promise.reject(error);
      }
    );
  };

  return [networkRequest, sendCommand];
}

Rispetto agli esempi precedenti, l’unica novità è la funzione useCommand, il resto è stato solo spostato da TodoItemForm (perché stiamo rendendo generica la gestione di una richiesta di rete di tipo “comando”).

Prima di capire perché useCommand è conveniente, utilizziamolo all’interno del componente TodoItemForm:

 

// File: src/components/TodoItemForm.jsx

import { useState } from "react";
import "./TodoItemForm.css";
import { NetworkRequestType, useCommand } from "../hooks/useCommand";

export default function TodoItemForm({ onSubmit }) {
  const [todoItem, setTodoItem] = useState({
    description: "",
    isDone: false,
  });

  const [createTodoItemNetworkRequest, createTodoItem] = useCommand({
    path: "/todo",
    method: "POST",
  });

  // onDescriptionChange e onIsDoneChange restano uguali

  const onFormSubmit = (event) => {
    event.preventDefault();

    createTodoItem(todoItem).then((response) => {
      onSubmit(response);
      setTodoItem({ description: "", isDone: false });
    });
  };

  const isLoading =
    createTodoItemNetworkRequest.type === NetworkRequestType.loading;

  return (
    <form className="TodoItemForm" onSubmit={onFormSubmit}>
      {/* anche il form rimane uguale */}
    </form>
  );
}

Abbiamo spostato tutta la gestione della richiesta di rete all’interno di useCommand.

La nuova funzione hook useCommand accetta come input il percorso e il metodo HTTP della chiamata di rete. L’argomento che accetta è uno solo, che racchiude entrambe le informazioni (path e method) per la stessa ragione per cui abbiamo fatto la stessa cosa con gli stati e per cui React la fa con le props: gli argomenti devono contenere tutte e sole le informazioni che descrivono l’argomento della funzione, in questo caso “la chiamata di rete quando non abbiamo ancora i dati a disposizione”.

La nuova funzione hook useCommand restituisce un array con due elementi: lo stato di rete – che utilizziamo nello stesso modo in cui l’abbiamo utilizzato precedentemente –  e la funzione per far partire la richiesta di rete. La funzione per far partire la richiesta di rete accetta come argomento i dati da inviare, sottolineando il fatto che i dati sono disponibili in un momento del tempo diverso dal percorso e dal metodo HTTP che descrivono la richiesta.

Nota: il fatto che useCommand restituisca un array con due elementi, come fa useState, è una coincidenza. Non c’è nessuna regola sul formato dei valori restituiti dalle funzioni hook, né sul formato o sulla quantità di argomenti che possono accettare.

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.