React · Guida per chi inizia

React da zero, in un quarto d'ora (il mio tutorial più visto su Youtube)

La versione scritta del mio video: in quindici minuti vediamo il JSX, come creare il tuo primo componente, le props, e le due Hook fondamentali — useState e useEffect — con il Virtual DOM che le rende possibili. Alla fine avrai anche un progetto da mettere nel portfolio.

Livello: principianteStack: React + ViteDurata: ~15 min29 giugno 20267 min di letturaSviluppo

Il video

Anteprima video YouTube
React JS — da zero a progetto portfolio · tutorial ita per junior frontend.Guarda su YouTube

Consiglio: guarda il video e tieni aperto questo articolo di fianco, così hai tutto il codice e i comandi pronti da copiare.

Prima di iniziare

01Cosa ti serve

L'obiettivo è chiaro: in poco tempo capire i mattoni fondamentali di React — JSX, il primo componente, le props, useState, useEffect e il Virtual DOM. Niente teoria infinita: si costruisce e si capisce facendo.

Per seguire sulla tua macchina ti servono due cose: Node.js installato e un editor a tua scelta. Io uso Visual Studio Code. Crea una cartella per il progetto (io l'ho chiamata react-youtube), aprila in VS Code e apri il terminale integrato: lavoreremo da lì.

Setup

02Crea il progetto con Vite

Useremo Vite, che è più veloce di Create React App. Dal terminale, in ordine, questi comandi. Il primo crea il progetto: my-react-app è il nome dell'applicazione (puoi cambiarlo), e come template scegliamo React — per ora senza TypeScript (magari lo vediamo in un prossimo video).

terminalebash
# 1. crea il progetto (template React, niente TypeScript per ora)
npm create vite@latest my-react-app

# 2. entra nella cartella appena creata
cd my-react-app

# 3. installa i node_modules necessari
npm install

# 4. avvia il server di sviluppo
npm run dev

Apri il localhost che ti suggerisce il terminale: la tua prima app React con Vite è già viva, e contiene perfino una piccola gestione di stato (un counter) che vedremo tra poco. Ma noi vogliamo partire dal pulito.

Vai in App.jsx — il componente principale — e cancella tutto ciò che ha generato Vite: via il counter, via gli import inutili. Puoi ripulire anche App.css (lascialo vuoto) e index.css. Così parti da una pagina bianca: ed è qui che inizia il bello.

Il cuore di React

03Il primo componente e il JSX

In React è tutto basato sui componenti. Un componente non è altro che una funzione che restituisce dell'HTML. Anzi, siamo in React, quindi non è proprio HTML: è JSX, un'estensione di JavaScript che ti permette di scrivere il markup dentro il codice.

Dentro src crea una cartella components: ci metteremo dentro tutti i componenti. Crea un file WelcomeMessage.jsx — per convenzione, i componenti React iniziano con la lettera maiuscola. Esporti una funzione che, nel return, ritorna un pezzo di JSX.

src/components/WelcomeMessage.jsxjsx
export function WelcomeMessage() {
  return <h1>Hello world 🚀</h1>
}

Salvi (Ctrl/Cmd + S) ma nel browser non vedi ancora niente: normale, perché il componente principale è App, quindi dobbiamo richiamare lì dentro il nuovo componente — proprio come fosse un tag HTML. L'editor ti suggerisce l'import dalla cartella components.

src/App.jsxjsx
import { WelcomeMessage } from './components/WelcomeMessage'

function App() {
  return <WelcomeMessage />   // tag auto-chiuso, stile HTML
}

export default App

Ecco il tuo primo componente custom in pagina. I vantaggi si vedono subito: niente "spaghetto" di un unico file HTML lunghissimo. Anche se WelcomeMessage fosse di cinquanta righe, in App resterebbe un solo tag pulito. E in più i componenti sono riutilizzabili: lo stesso componente puoi ripeterlo tante volte (in un map, in un fetch…). Ma duplicarlo identico a sé stesso non serve a molto — ed è qui che entrano le props.

Riutilizzo

04Le props: stesso componente, dati diversi

Le props sono i parametri che passi a un componente per riutilizzarlo con contenuti diversi. Diciamo che WelcomeMessage riceve in ingresso un message, e lo mettiamo al posto di "Hello world" rendendolo dinamico.

WelcomeMessage.jsxjsx
export function WelcomeMessage({ message }) {
  return <h1>{message}</h1>
}

// in App, passi la prop come un attributo HTML:
<WelcomeMessage message="Hello world" />
<WelcomeMessage message="Ciao ragazzi, un like al video!" />

E se chiami WelcomeMessage senza passare la prop? Non ritorna nulla, perché si aspetta un messaggio. Per evitarlo gli diamo un valore di default con l'operatore ||: se la prop non arriva, usa quello.

props con defaultjsx
export function WelcomeMessage({ message }) {
  return <h1>{message || 'Messaggio di default'}</h1>
}

Ora però sono tutti h1, e non va benissimo. Sempre con le props possiamo dire che solo uno è un titolo, passando una prop booleana title. Si scrive title={true}, o, in forma ridotta, solo title. Per usarla nel return apriamo le parentesi tonde (il return è più complesso di una riga) e usiamo l'operatore ternario dentro le graffe — le graffe sono "qui scrivo JavaScript dentro il JSX": se è un titolo lo rendiamo h1, altrimenti un semplice paragrafo.

prop booleana + ternario + Fragmentjsx
export function WelcomeMessage({ message, title }) {
  return (
    <>
      {title
        ? <h1>{message || 'Messaggio di default'}</h1>
        : <p>{message || 'Messaggio di default'}</p>}
    </>
  )
}

// in App: solo questo è un titolo
<WelcomeMessage message="Hello world" title />
<WelcomeMessage message="Ciao ragazzi" />

Attenzione a un dettaglio: il return deve essere un solo blocco JSX. O racchiudi tutto in un <div>, oppure usi il React Fragment <>...</> — è come un tag vuoto che non aggiunge un elemento HTML inutile alla pagina.

Perché è potenteInvece di copiare e incollare lo stesso markup nell'HTML, immagina una card con immagine, titolo e descrizione: crei un solo componente con un layout e, grazie alle props, lo riutilizzi all'infinito con contenuti diversi.

La prima Hook

05useState e il Virtual DOM

La prima Hook è useState: ci permette di aggiornare in modo dinamico il Virtual DOM senza ricaricare la pagina. Creiamo components/Counter.jsx. Stavolta, per mostrarti un altro modo di scrivere le funzioni, uso una arrow function (più compatta).

Vogliamo che accanto a "counter:" ci sia il valore di un contatore, incrementato da un bottone. Dichiariamo la variabile con useState — che va importata da react — passandogli il valore iniziale 0. Ci restituisce due cose: il valore (count) e la funzione per aggiornarlo (setCount).

components/Counter.jsxjsx
import { useState } from 'react'

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

  return (
    <div>
      <p>counter: {count}</p>
      <button onClick={() => setCount(count + 1)}>
        incrementa
      </button>
    </div>
  )
}

export default Counter

Nota l'onClick: tutti i listener di JavaScript ci sono anche nel JSX. Al click, setCount imposta count + 1, React se ne accorge e ri-disegna solo quel pezzo — senza refresh della pagina. Questa è la potenza del Virtual DOM.

Per legare i concetti: il valore iniziale può arrivare da una prop. Lo chiamiamo start e lo passiamo da App, così possiamo avere due contatori indipendenti che partono da valori diversi.

valore iniziale da propjsx
// Counter.jsx
const Counter = ({ start }) => {
  const [count, setCount] = useState(start)
  // ...resto uguale
}

// App.jsx: due contatori, indipendenti tra loro
<Counter start={1} />
<Counter start={100} />
La chicca dello "zero"Far partire il contatore da 0 dà un comportamento strano: in JavaScript lo 0 è "falsy", cioè viene trattato un po' come un valore vuoto, e senza TypeScript la cosa può sfuggire. Per la demo lo facciamo partire da 1: è un caso particolare che merita un video a parte.

In poche righe abbiamo due componenti che fanno la stessa cosa partendo da valori diversi, in modo indipendente e senza refresh: una cosa che in HTML e JavaScript "vanilla" sarebbe parecchio più complessa da replicare.

La seconda Hook

06useEffect: chiamare un'API

Finora abbiamo reso dinamici dei valori nel frontend. Ma la vera dinamicità arriva quando i dati vengono da un backend. La Hook useEffect ci serve per fare le chiamate API quando il componente viene montato.

Usiamo un'API pubblica, randomuser.me/api, che ritorna i dati di una persona casuale. Creiamo components/RandomUser.jsx. Mettiamo l'utente in uno stato (user / setUser) e con un ternario mostriamo i dati se ci sono, altrimenti un "caricamento…" finché l'API non risponde.

components/RandomUser.jsxjsx
import { useState, useEffect } from 'react'

export const RandomUser = () => {
  const [user, setUser] = useState()

  useEffect(() => {
    fetch('https://randomuser.me/api')
      .then((res) => res.json())
      .then((data) => setUser(data.results[0]))
  }, [])   // [] = eseguito quando il componente si monta

  return (
    <>
      {user
        ? (
          <div>
            <img src={user.picture.medium} alt="avatar" />
            <p>{user.name.first} {user.name.last}</p>
            <p>{user.email}</p>
          </div>
        )
        : <p>caricamento…</p>}
    </>
  )
}

Due cose sulla struttura. L'array vuoto [] alla fine di useEffect dice "esegui solo al montaggio"; lì dentro potresti mettere delle dipendenze (es. ri-eseguire quando cambia user), ma a noi serve al mount. E attenzione al JSON dell'API: il nome non è user.title (quello è "Mr/Miss"), ma user.name.first — un classico errore da controllare guardando la struttura dei dati.

Perché l'API parte due volte?Al refresh noterai due chiamate nel pannello Network: è la StrictMode di React, che in sviluppo monta i componenti due volte di proposito per aiutarti a scovare bug. Non succede in produzione. Commentando la StrictMode resta una sola chiamata — ma il "perché" è roba da un altro video.

Il progetto

07Una To-Do list per il portfolio

Per chiudere, un progetto vero da mettere nel portfolio: una To-Do list, costruita con lo useState che hai appena imparato. Servono due variabili di stato: tasks (l'elenco) e task (quello che stai scrivendo). La versione completa la trovi nel repository GitHub linkato nella descrizione del video; qui sotto la struttura essenziale, con aggiunta ed eliminazione.

components/TodoList.jsxjsx
import { useState } from 'react'

export const TodoList = () => {
  const [tasks, setTasks] = useState([])
  const [task, setTask] = useState('')

  const addTask = () => {
    if (!task) return
    setTasks([...tasks, task])   // aggiungo in coda
    setTask('')               // svuoto l'input
  }

  const removeTask = (i) =>
    setTasks(tasks.filter((_, index) => index !== i))

  return (
    <div>
      <input value={task} onChange={(e) => setTask(e.target.value)} />
      <button onClick={addTask}>Aggiungi</button>
      <ul>
        {tasks.map((t, i) => (
          <li key={i}>
            {t} <button onClick={() => removeTask(i)}>Elimina</button>
          </li>
        ))}
      </ul>
    </div>
  )
}
Esercizio per teQui ci sono aggiungi e rimuovi: prova ad aggiungere anche la modifica (edit) di un task, e un po' di CSS per stilare i campi. Quando l'hai finita, fanne uno screenshot e taggami — è un ottimo pezzo da mostrare nel portfolio.

Conclusione

08Cosa hai imparato

Arrivato qui sai creare componenti React, usare le due Hook principali — useState e useEffect — e perfino caricare dati da un'API. È l'infarinatura iniziale giusta per partire sul serio.

Ho lasciato apposta da parte due argomenti, perché meritano spazio: il caso dello zero nelle props e la StrictMode col doppio fetch. Se vuoi che ne parli, o vuoi concetti più avanzati, scrivimelo nei commenti.

Anteprima video YouTube
Segui passo passo: guarda il tutorial completo su YouTube · il repo della To-Do è in descrizione.Guarda su YouTube

Per approfondire: react.dev

Blog

Altri articoli

Cosa ne pensi dell'articolo? Parliamone...