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:
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
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;
}
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:
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;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. {count}
mostra la variabile di stato nell'elemento creato da CounterLa 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.
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;
Un operatore ternario è un operatore condizionale che può essere utilizzato al posto di un'istruzione if-else. Un operatore ternario è composto da tre parti:
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"
Integriamo in un componente l'esercizio di ieri, creando un div che ci mostra la temperatura.
Creiamo un nuovo componente chiamato "Weather.js".
Importiamo React, useState e useEffect da 'react'
Creiamo le necessarie variabili, const [weatherData,setWeatherData], la città, l'url etc.
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.
Creiamo una serie di variabili per salvarvi dentro i dati del JSON, ovvero nome città, condizione meteo, descrizione, temperatura.
Ritorniamo tutto in un div, e una volta fatto inseriamo l'elemento WeatherCard nella nostra App.js.
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.