Framework: React

Keywords: virtual dom, React

Esercizio precedente Esercizio successivo

React

React è un framework per creare interfacce utente efficienti e scalabili. Ciò significa che React ci aiuta a scrivere codice più organizzato e riutilizzabile, attraverso la suddivisione dell'interfaccia in componenti.

Concetti chiave per React:

  1. Componenti: blocchi di codice che rappresentano unità logiche dell'interfaccia utente
  2. Props: proprietà passate ai componenti per visualizzare i dati dinamici
  3. Stato (state): oggetto che contiene i dati dinamici del componente
  4. Renderizzazione: processo attraverso cui React ricalcola la visualizzazione del componente quando lo stato cambia
  5. DOM virtuale (Virtual DOM): rappresentazione in memoria del DOM del browser
  6. Riutilizzo dei componenti: possibilità di utilizzare lo stesso componente in più parti dell'interfaccia
  7. Gestione degli eventi: possibilità di gestire gli eventi utente come clic del mouse o tastiera
  8. JSX: sintassi che permette di scrivere codice HTML all'interno del codice JavaScript
  9. React Router: libreria per la gestione delle rotte dell'applicazione (pagine e URL)
  10. Flusso di dati unidirezionale: principio che prevede il flusso dei dati dal componente padre ai componenti figli

npx

Comando per eseguire pacchetti npm direttamente dal terminate senza installarli globalmente;

Per creare un sito con React, solitamente:

npx create-react-app my-app

Questo comando installa automaticamente i seguendi pacchetti in una cartella my-app

  1. react e react-dom: librerie React principali per la creazione di interfacce utente
  2. react-scripts: collezione di script preconfigurati per la gestione del progetto React, tra cui lo sviluppo locale e la creazione di un build per la produzione
  3. babel: strumento per la conversione del codice JavaScript moderno in una forma compatibile con i browser più vecchi
  4. webpack: strumento per la creazione di pacchetti di codice JavaScript e la gestione delle dipendenze tra i moduli
  5. eslint: strumento per la verifica del codice JavaScript contro le best practice e le convenzioni del codice
  6. E molte altre.

Componenti

La nostra app comincia qui, dal file App.js che troviamo nella cartella src. Al suo interno troveremo il template precompilato. Qui vediamo che l'App renderizza un div con all'interno un elemento Titolo (autochiudente) che ha un "attributo" pari a "Ciao!".

Già possiamo vedere in poche righe molte delle caratteristiche di React.

import React from 'react';
import Titolo from './Titolo';

function App() {
  return (  
<div>
  <Titolo testo="Ciao!" />
</div>
  );
}

export default App;

Qui vediamo il componente Titolo, che si trova nel file "Titolo.js". Esso, oltre ad importare React, utilizza una funzione che ritorna un h1 con la variabile "props.testo", che è stata passata dal componente padre.

import React from 'react';

function Titolo(props) {
  return <h1>{props.testo}</h1>;
}

export default Titolo;

Se qualcosa vi sembra meno familiare del solito è normale. La sintassi di React (JSX) mischia Javascript e markup HTML.

Alcuni esempi:

  • // JSX
    const element = <h1>Hello, world!</h1>;
    
    // JavaScript
    const element = document.createElement('h1');
    element.textContent = 'Hello, world!';
    
  • Qui vediamo come un componente, in questo caso creato come una funzione, sfrutti "props", ovvero le proprietà del parent, per riempire sé stesso. In questo caso, il componente MyComponent riceve due props, title e content, che vengono poi utilizzate per riempire un div con un h1 e un p.

    La funzione JS, seppur facendo virtualmente la stessa cosa, va gestita in maniera molto diversa (ma vediamo sempre come in realtà la sostanza sia la stessa).

      // JSX
    function MyComponent(props) {
      return (
        <div>
          <h1>{props.title}</h1>
          <p>{props.content}</p>
        </div>
      );
    }
    
          // JavaScript
    function MyComponent(props) {
      const element = document.createElement('div');
      const heading = document.createElement('h1');
      const paragraph = document.createElement('p');
      heading.textContent = props.title;
      paragraph.textContent = props.content;
      element.appendChild(heading);
      element.appendChild(paragraph);
      return element;
    }

Stati

Il componente Counter utilizza il metodo useState per creare uno stato interno con il valore iniziale di 0. Viene quindi utilizzata la funzione setCount per aggiornare il valore dello stato quando l'utente fa clic sul pulsante. Questo valore viene quindi visualizzato all'interno del componente utilizzando la sintassi JSX.

In sintesi, gli stati sono utilizzati in React per tenere traccia delle informazioni che possono cambiare nel tempo. Quando uno stato viene aggiornato, React renderizza il componente di nuovo per visualizzare le modifiche. Questo è un esempio semplice ma utile per spiegare il concetto di stato in React.

import React, { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);

  function handleClick() {
    setCount(count + 1);
  }

  return (
    <div>
      <h2>Contatore di clic: {count}</h2>
      <button onClick={handleClick}>Clicca qui</button>
    </div>
  );
}

export default Counter;

Quando lo stato di un componente cambia, React aggiorna automaticamente la visualizzazione dell'interfaccia utente per riflettere questo cambiamento. React utilizza il concetto di "Virtual DOM" per effettuare questi aggiornamenti in modo efficiente. Il Virtual DOM è una rappresentazione virtuale della struttura dell'interfaccia utente di un'applicazione React. Quando lo stato di un componente cambia, React genera una nuova versione del Virtual DOM, confronta questa nuova versione con quella precedente e calcola la differenza tra le due versioni. Questa differenza viene quindi applicata all'interfaccia utente reale, ma solo per gli elementi che effettivamente sono cambiati.

In particolare:

  1. useState(): variabile di stato all'interno del componente. La funzione accetta un valore e restituisce un'array che contiene la variabile e una funzione per aggiornare quello stato;
  2. setCount(): funzione di React che accetta il valore della variabile di stato associata: qui handleClick chiama setCount per aggiornare la variabile di stato count di 1.
  3. {count} mostra la variabile di stato nell'elemento creato da Counter

La sintassi [count, setCount] viene utilizzata per assegnare i valori di ritorno della funzione useState rispettivamente alla variabile count e alla funzione setCount. In questo modo, count rappresenta il valore corrente della variabile di stato e setCount è una funzione che viene utilizzata per aggiornare il valore della variabile di stato count.

One-way data flow

In React i dati fluiscono dal componente padre a quello figli attraverso gli oggetti props. I componenti figli possono visualizzare dati e utilizzarli, ma non modificarli: per fare ciò, l'elemento figlio deve modificare i dati seguendo una callback.

import React, { useState } from 'react';
//ParentComponent utilizza al suo interno ChildComponent, a cui passa una prop name e una funzione onInputChange
function ParentComponent() {
  const [name, setName] = useState("");

/*
In generale, il nome della variabile iniziale 
viene scritto in camel case, come name, mentre 
il nome della funzione di aggiornamento dello stato 
viene creato concatenando "set" al nome della variabile, 
in Pascal case, come setName.
*/

  function handleInputChange(event) {
    setName(event.target.value);
  }

  return (
    <div>
      <h2>Ciao, {name}!</h2>
      <ChildComponent name={name} onInputChange={handleInputChange} />
    </div>
  );
}

/*
Ogni volta che l'utente inserisce un valore nell'input, 
la funzione handleInputChange viene chiamata.
Questa funzione aggiorna il valore della variabile di stato 
name utilizzando la funzione setName.

=====> setName(event.target.value); 

Dato che la funzione handleInputChange viene passata 
a ChildComponent come prop ed è stata dichiarata nel 
parent component, la funzione potrà modificare il valore 
della variabile di stato name, anche se interagisce col child component.

A sua volta, il ParentComponent aggiorna il valore della variabile in 
base alla callback
*/

function ChildComponent(props) {
  return (
    <div>
      <label htmlFor="name-input">Inserisci il tuo nome:</label>
      <input id="name-input" type="text" value={props.name} onChange={props.onInputChange} />
    </div>
  );
}

export default ParentComponent;

Operatori ternari

Un operatore ternario è un operatore condizionale che può essere utilizzato al posto di un'istruzione if-else. Un operatore ternario è composto da tre parti:

  • una condizione;
  • un'espressione che viene valutata se la condizione è vera;
  • un'espressione che viene valutata se la condizione è falsa.
condizione ? espressione_true : espressione_false
let x = 5;
  let result = x > 10 ? "x è maggiore di 10" : "x è minore o uguale a 10";
  console.log(result); // Output: "x è minore o uguale a 10"  

Esercizio di oggi

Integriamo in un componente l'esercizio di ieri, creando un div che ci mostra la temperatura.

Parte 1

  1. Creiamo un nuovo componente chiamato "Weather.js".

  2. Importiamo React, useState e useEffect da 'react'

  3. Creiamo le necessarie variabili, const [weatherData,setWeatherData], la città, l'url etc.

  4. Usiamo useEffect() per fare una fetch all'API di Openweathermap.

      useEffect(() => {
          fetch(url)
          .then(response => response.json())
            .then(data => setWeatherData(data));
        }, []);

    useEffect viene chiamato la prima volta all'avvio del componente.

Parte 2

Creiamo una serie di variabili per salvarvi dentro i dati del JSON, ovvero nome città, condizione meteo, descrizione, temperatura.

Parte 3

Ritorniamo tutto in un div, e una volta fatto inseriamo l'elemento WeatherCard nella nostra App.js.

Per casa:

Provate a fare lo stesso esercizio di ieri su React, creando un componente che mostra una lista di opzioni, e un'altro che fa la chiamata all'API.


© Andrea Schimmenti & Fabio Vitali. TW 2022-2023.