React e async await: Interagire con un API
Troverai nel progetto
Che cosa realizzeremo in questo progetto ?
Fetcheremo dei dati da un'API, con cui creeremo il menù di un Gelateria che prevederà 4 categorie: all, cono, coppette e stick. Il nostro utente atterrerà con la voce 'all' preselezionata e grazie a una navigazione in tab potrà passare da una categoria all'altra.
Di che cosa avremmo bisogno ?
- useState: Ci serviranno più state per tenere traccia del loading, eventuali errori, i prodotti, le categorie, la categoria selezionata e i prodotti filtrati in base alla categoria attiva.
const [isLoading, setIsLoading] = useState(true); const [isError, setIsError] = useState(false); const [prodotti, setProdotti] = React.useState(); const [categorie, setCategorie] = useState([]); const [filterProducts, setFilterProducts] = useState(); const [selceted, setSelected] = useState(0);
- useEffect: Necessario per fetchare i dati dalla nostra API
- API: https://react--course-api.herokuapp.com/api/v1/data/gelateria
Usare useEffect per fetchare dati da un API
Iniziamo fetchando i dati da un API. In questo esempio useremo una IIFE, ovvero una funzione invocata immediatemente dopo la definizione. Questo perché in React quando usiamo lo useEffect non possiamo definire la callback function come asyncrona.
//Ritornerà un errore React.useEffect(async () => ... , [])
Per risolvere questo problema abbiamo due opzioni:
- Definire una funzione asyncrona all'esterno dello useEffect e richiamarla al suo interno
- Definire una funzione ayncrona nel corpo dello useEffect ed invocarla. Noi sceglieremo quest'ultima
React.useEffect(() => { //IIFE (async () => { setIsLoading(true); setIsError(false); try { const response = await axios.get(url); setProdotti(response.data.data); setFilterProducts(response.data.data); //Ottengo Array di elementi non ripetibili const nuoveCategorie = Array.from( new Set(response.data.data.map((el) => el.categoria)) ); //Aggiungo all'inizio termine all nuoveCategorie.unshift("all"); setCategorie(nuoveCategorie); //Termino Caricamento setIsLoading(false); } catch (error) { //Errore setIsError(true); setIsLoading(false); console.log(error); } })(); }, []);
Filtrare un Array in React
Ora dobbiamo gestire la navigazione dell'utente tramite il menu e filtrare l'array di prodotti in base alla scelta del nostro utente. Per fare questo definiremo una funzione che ci permetta di updatare entrambi i nostri state di select e filteredProduct.
const filtraProdotti = (categoria, index) => { setSelected(index); //Se indico "all" ripristino allo stato iniziale if (categoria === "all") { setFilterProducts(prodotti); } //Se no uso filter Method else { const prodottiFiltrati = prodotti.filter((el) => el.categoria === categoria ? el : "" ); setFilterProducts(prodottiFiltrati); } };
Per selected andiamo ad utilizzare un numero in modo da poter controllare grazie alla posizione che occupa all'intenro dell'array di categorie, quale sia la categoria attiva.
<div className="lista-categorie"> {categorie.map((categoria, index) => ( <button className={`btn btn-selector ${ selceted === index && "active" }`} key={index} data-categoria={categoria} onClick={() => filtraProdotti(categoria, index)} > {categoria} </button> ))} </div>