
GUIDE PER ASPIRANTI PROGRAMMATORI
Gestione dell’interfaccia: metodo dichiarativo
Quando scegliamo un approccio dichiarativo, la prima domanda che ci poniamo è: cosa vogliamo rappresentare? Questa domanda rivela già una cosa importante: è vero, stiamo lavorando sull’aspetto del form, ma l’aspetto del form dipende direttamente dalla richiesta di rete che effettua il salvataggio dei dati. Ed è quello che vogliamo rappresentare: non il form, ma…


Vuoi avviare una nuova carriera o fare un upgrade?
Trova il corso Digital & Tech più adatto a te nel nostro catalogo!
Quando scegliamo un approccio dichiarativo, la prima domanda che ci poniamo è: cosa vogliamo rappresentare? Questa domanda rivela già una cosa importante: è vero, stiamo lavorando sull’aspetto del form, ma l’aspetto del form dipende direttamente dalla richiesta di rete che effettua il salvataggio dei dati. Ed è quello che vogliamo rappresentare: non il form, ma la richiesta di rete.
La seconda domanda che ci poniamo è: quali sono le informazioni che descrivono quello che vogliamo rappresentare? Possiamo descrivere la richiesta di rete in quattro casi:
- Inattivo: la richiesta non è ancora avvenuta.
- Caricamento: il salvataggio sta succedendo, ma non sappiamo ancora come andrà.
- Successo: il salvataggio è avvenuto, e conosciamo il suo risultato.
- Fallimento: il salvataggio è avvenuto e ha fallito. Conosciamo la ragione per cui ha fallito.
A questo punto, possiamo costruire una base su cui costruire la nostra descrizione:
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 }; }
Abbiamo definito i quattro stati della richiesta, rappresentati con degli oggetti. In qualsiasi momento del tempo, una chiamata di rete sarà rappresentata da un oggetto. L’oggetto ha sempre una proprietà type che ci dice in quale dei quattro stati è la richiesta. L’oggetto ha una proprietà response, che contiene i dati della risposta, solo quando lo stato è “successo”. L’oggetto ha una proprietà error, che contiene la ragione del fallimento, solo quando lo stato è “fallimento”.
Abbiamo anche creato quattro funzioni, che ci aiutano a creare richieste di rete nei diversi stati. In aiuto abbiamo anche NetworkRequestType, un oggetto che contiene la mappa di tutti e soli gli stati che una richiesta di rete può assumere.
A questo punto, possiamo integrare tutto nel nostro componente:
// File: src/components/TodoItemForm.jsx import { useState } from "react"; import "./TodoItemForm.css"; 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({ todoItem, onChange, onSubmit }) { const [networkState, setNetworkState] = useState(makeIdleNetworkRequest()); // ... const onFormSubmit = (event) => { event.preventDefault(); setNetworkState(makeLoadingNetworkRequest()); onSubmit().then( (todoItem) => { setNetworkState(makeSuccessfulNetworkRequest(todoItem)); }, (error) => { setNetworkState(makeFailedNetworkRequest(error.message)); } ); }; const isLoading = networkState.type === NetworkRequestType.loading; return ( <form className="TodoItemForm" onSubmit={onFormSubmit}> <input type="checkbox" checked={todoItem.isDone} onChange={(event) => { onIsDoneChange(event.currentTarget.checked); }} disabled={isLoading} /> <input type="text" placeholder="Description" value={todoItem.description} onInput={(event) => { onDescriptionChange(event.currentTarget.value); }} disabled={isLoading} /> <input type="submit" value="Create" disabled={isLoading} /> {networkState.type === NetworkRequestType.failure ? ( <p style={{ color: "red" }}>{networkState.error}</p> ) : null} </form> ); }
Abbiamo creato uno stato per rappresentare la richiesta di rete che effettua il salvataggio dei dati. Lo stato è inizializzato nello stato “inattivo”. Al click del bottone “Create”, lo stato passa a “caricamento”. A seconda dell’andamento della richiesta, lo stato passa a “successo” o “errore”.
Le funzioni che abbiamo creato per aiutarci coincidono perfettamente con i dati che abbiamo a disposizione quando lo stato cambia: passiamo todoItem in caso di successo ed error.message in caso di fallimento.
Abbiamo creato una costante, isLoading, che rappresenta il fatto che la richiesta sia in stato di “caricamento”. In caso di fallimento, estraiamo l’errore dallo stato e lo visualizziamo.
Questo esempio dovrebbe averti chiarito la differenza tra approccio imperativo e approccio dichiarativo nella gestione delle interfacce utente in React. Pronto per i prossimi capitoli?
CONTENUTI GRATUITI IN EVIDENZA
Guide per aspiranti programmatori 👨🏻🚀
Vuoi muovere i primi passi nel Digital e Tech? Abbiamo preparato alcune guide per aiutarti a orientarti negli ambiti più richiesti oggi.