Stati con liste in React | Aulab

GUIDE PER ASPIRANTI PROGRAMMATORI

Stati con liste in React

Pronto a mettere le mani in pasta? Mettiamo in pratica quello che abbiamo appena imparato! Modifichiamo la nostra applicazione per mantenere uno stato della lista di cose da fare. Alla creazione di un nuovo elemento, dopo aver mandato la nostra finta richiesta di rete, aggiungiamo il nuovo elemento in cima alla lista. Alla fine di…

Lezione 22 / 41
Enza Neri
Immagine di copertina

Vuoi avviare una nuova carriera o fare un upgrade?

Trova il corso Digital & Tech più adatto a te nel nostro catalogo!

Pronto a mettere le mani in pasta? Mettiamo in pratica quello che abbiamo appena imparato!

Modifichiamo la nostra applicazione per mantenere uno stato della lista di cose da fare. Alla creazione di un nuovo elemento, dopo aver mandato la nostra finta richiesta di rete, aggiungiamo il nuovo elemento in cima alla lista.

Alla fine di questa modifica, la nostra applicazione avrà due stati: lo stato della lista di cose da fare, che possiamo chiamare todoList e lo stato dell’elemento che sta venendo creato, che coincide con lo stato todoItem che abbiamo in questo momento.

Ricordi quando dicevamo che avere lo stato todoItem all’interno di App poteva non essere la soluzione migliore? Bene, questo è il momento di riportarlo in TodoItemForm. Lo stato todoItem è legato solamente all’aspetto del form (in altre parole, l’aspetto del form dipende dallo stato todoItem), mentre App non si occupa di quella parte del sistema. App avrà invece il compito di occuparsi della lista intera, cioè il nuovo stato todoList.

// File: src/components/TodoItemForm.jsx

import { createTodoItem } from "../mock/createTodoItem";
import { useState } from "react";
import "./TodoItemForm.css";

/* ... */

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

  const [networkState, setNetworkState] = useState(makeIdleNetworkRequest());

  const onDescriptionChange = (description) => {
    setTodoItem((todoItem) => {
      return {
        ...todoItem,
        description,
      };
    });
  };

  const onIsDoneChange = (isDone) => {
    setTodoItem((todoItem) => {
      return {
        ...todoItem,
        isDone,
      };
    });
  };

  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));
      }
    );
  };

  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 riportato lo stato todoItem all’interno di TodoItemForm. Al submit, inviamo la richiesta di rete per il salvataggio dei dati direttamente da qui. Se il salvataggio avviene correttamente, allora notifichiamo App dell’avvenuta creazione dell’elemento, passando alla prop onSubmit i relativi dati.

Con questo cambiamento, il componente App non avrà altre interazioni con TodoItemForm se non nel caso in cui un nuovo elemento è stato creato. Tutta la fase di creazione dell’elemento è gestita internamente dal componente TodoItemForm, creando una separazione dei compiti ben definita.

// File: src/App.jsx

import { useState } from "react";
import "./App.css";
import Panel from "./components/Panel";
import TodoItemForm from "./components/TodoItemForm";

export default function App() {
  const [todoList, setTodoList] = useState([]);

  const onTodoItemFormSubmit = (todoItem) => {
    return setTodoList((todoList) => [todoItem, ...todoList]);
  };

  return (
    <div className="App">
      <Panel>
        <TodoItemForm onSubmit={onTodoItemFormSubmit} />
      </Panel>
    </div>
  );
}

La quantità di logica gestita dal componente App è diminuita sostanzialmente e si vede dalle dimensioni del componente. Ora App ha due compiti: mantenere lo stato della lista di cose da fare e aggiungere nuovi elementi che arrivano da TodoItemForm, sapendo che tutta la fase di validazione e salvataggio è gestita internamente dal componente figlio.

Se hai ESLint acceso e/o stai usando Create React App, noterai un avvertimento: non stiamo utilizzando todoList! Per adesso, questa cosa non ha importanza ma l’avvertimento ci aiuterà a tenerlo presente.

Le liste in JSX

Quando abbiamo uno stato che contiene un array, in React, utilizziamo tipicamente il metodo map di Array per trasformarlo in un array di elementi JSX.

// File: src/App.tsx

// ...

export default function App() {
  const [todoList, setTodoList] = useState([]);

  // ...

  return (
    <div className="App">
      <div className="TodoList">
        {todoList.map((todoItem, index) => {
          return (
            <div className="TodoItem" key={index}>
              <input type="checkbox" value={todoItem.isDone} disabled />
              <span>{todoItem.description}</span>
            </div>
          );
        })}
      </div>
      {/* ... */}
    </div>
  );
}

Spoiler alert: nei prossimi paragrafi parleremo un sacco di componenti, elementi, proprietà e attributi. Per fare un rapidissimo ripasso: in JSX, parliamo di elementi e attributi in riferimento agli elementi HTML, riconoscibili per la prima lettera minuscola. Parliamo, invece, di componenti e proprietà (o props) in riferimento ai componenti di React, riconoscibili dalla prima lettera maiuscola. Quando si parla di JSX in generale, parlare di componenti o elementi è equivalente, perché JSX contiene un misto di entrambi.

Abbiamo trasformato una lista di elementi di cose da fare, con le loro proprietà description e isDone, in una lista di elementi JSX. Possiamo notare un paio di cose:

  • Per ogni concetto della nostra app, c’è un elemento HTML: l’intera app è circondata da un div, la lista è rappresentata da un div, c’è un div per ogni elemento della lista e un elemento HTML per ogni proprietà dell’elemento della lista (span per description, input[type=checkbox] per isDone). Creare una correlazione 1:1 tra parti della struttura dati ed elementi HTML può essere incredibilmente utile per mantenere un alto livello di confidenza sulla qualità del codice.
  • L’elemento div.TodoItem ha un attributo/proprietà key. key è una delle tre proprietà sempre valide in React (abbiamo visto children in precedenza) e definisce l’unicità di un elemento o componente in una lista. Merita una sezione a sé. Approfondiamola nel prossimo capitolo!

Sei indeciso sul percorso? 💭

Parliamone! Scrivici su Whatsapp e risponderemo a tutte le tue domande per capire quale dei nostri corsi è il più adatto alle tue esigenze.

Oppure chiamaci al 800 128 626