Menu

Domande colloquio React con risposte (React 19)

Circa 30 domande da colloquio su React dal livello principiante a quello avanzato, ognuna con una risposta breve che un selezionatore accetterebbe e codice dal vivo per quelle più facili da vedere che da leggere.

Questa pagina include editor eseguibili: modifica, esegui e vedi subito l'output.

Queste sono le domande da colloquio su React che ricorrono più spesso, raggruppate per livello e con le risposte che un selezionatore si aspetta: brevi, corrette per React 19 e con il motivo dietro la regola. Dove vedere il comportamento è meglio che leggerlo, la risposta ha un editor dal vivo, e alcune domande ti chiedono di prevedere l'output della console prima di eseguire il codice.

Prima di cliccare: cosa stampa la console sotto l'anteprima, e cosa mostra il pulsante? La risposta è nella sezione per principianti qui sotto.

Domande per principianti

Cos'è React?

React è una libreria JavaScript per costruire interfacce utente a partire da componenti. Scrivi funzioni che restituiscono una descrizione della UI per i dati attuali, e quando quei dati cambiano React capisce cosa è cambiato e aggiorna il DOM per te. Si occupa solo dello strato della vista: routing, recupero dei dati e form arrivano da altre librerie o da un framework come Next.js.

Cos'è JSX?

JSX è un'estensione della sintassi che ti permette di scrivere markup dentro JavaScript. Un compilatore (Babel, esbuild, SWC) trasforma ogni tag in una chiamata che crea un elemento React, quindi <p className="note">{text}</p> diventa un oggetto con type: 'p' e le props. Poiché è JavaScript, usi className al posto di class, metti le espressioni tra {}, e ogni tag deve essere chiuso. La pagina su JSX tratta le regole in dettaglio.

Qual è la differenza tra un componente e un elemento?

Un componente è una funzione (o una classe) che riceve props e restituisce UI. Un elemento è il semplice oggetto prodotto da JSX, che descrive cosa renderizzare: <Avatar size={40} /> è un elemento il cui type è la funzione Avatar. React chiama il tuo componente per trasformare elementi in altri elementi, fino ad arrivare ai tag DOM. Gli elementi costano poco e sono immutabili; non chiami mai tu un componente.

Qual è la differenza tra props e stato?

Le props vengono passate dal genitore e dentro il componente sono di sola lettura. Lo stato è posseduto dal componente, cambia nel tempo tramite un setter, e ogni cambiamento programma un nuovo render. Un modo comune per dirlo: le props configurano un componente, lo stato è la sua memoria. Lo stesso valore può essere stato in un genitore e prop nel suo figlio.

Cosa registra il primo esempio di questa pagina?

Registra logged: 0, e il pulsante mostra Count: 1, non 2. Lo stato è un'istantanea: count è una costante per tutto il rendering, quindi entrambe le chiamate setCount(count + 1) calcolano 0 + 1, e il log legge il vecchio valore perché quello nuovo esiste solo nel rendering successivo. Per aggiungere due, usa la forma con funzione di aggiornamento: setCount((c) => c + 1) due volte.

Perché le liste hanno bisogno delle key, e perché l'indice è una cattiva key?

React usa la key per abbinare ogni voce della lista a quella del rendering precedente. Se usi l'indice dell'array e inserisci una voce in cima, ogni indice si sposta, quindi React tiene lo stato di ogni riga nella sua vecchia posizione e lo collega ai dati sbagliati.

Spunta Ada, poi clicca "Add to top": la spunta salta sulla nuova prima riga. Cambia key={index} in key={person.id} e riprova, e la spunta resta con Ada. In sviluppo React avvisa anche quando mancano le key; l'anteprima gira come una build di produzione, quindi qui non vedrai quell'avviso.

Cos'è un input controllato?

Un input il cui valore arriva dallo stato React: passi value e aggiorni lo stato in onChange, quindi React è l'unica fonte di verità e puoi validare o trasformare ogni tasto. Un input non controllato tiene il proprio valore nel DOM e lo leggi quando serve, tramite un ref o i FormData del form. Gli input controllati sono la scelta predefinita quando la UI reagisce a ciò che l'utente scrive.

Cosa significa sollevare lo stato?

Quando due componenti hanno bisogno degli stessi dati, sposti lo stato nel loro genitore comune più vicino e lo passi verso il basso come props, insieme a una funzione per cambiarlo. I figli smettono di possedere copie proprie, quindi non possono mai essere in disaccordo. È la risposta standard a "come condividono lo stato i componenti fratelli" prima di ricorrere al context o a uno store.

Quali sono le regole degli hook?

Chiama gli hook solo al livello più alto di un componente o di un hook personalizzato, mai dentro condizioni, cicli o funzioni annidate, e solo da funzioni React, non da semplici funzioni JavaScript. React identifica ogni hook dall'ordine delle chiamate, quindi quell'ordine deve essere identico a ogni rendering. Il pacchetto eslint-plugin-react-hooks impone entrambe le regole.

Cos'è un fragment?

Un fragment raggruppa più elementi senza aggiungere un nodo DOM: <>...</>, oppure <Fragment key={id}> quando ti serve una key dentro una lista. Un componente deve restituire una sola radice, e i fragment permettono che quella radice siano più fratelli, il che conta dentro tabelle e layout flex dove un div in più romperebbe il markup.

Domande di livello intermedio

Come funziona l'array delle dipendenze di useEffect?

React esegue l'effetto dopo che il rendering è stato applicato (di solito dopo che il browser ha disegnato la pagina), poi di nuovo dopo ogni rendering successivo in cui un valore dell'array è cambiato (confrontato con Object.is). Senza array viene eseguito dopo ogni rendering; con [] viene eseguito una volta dopo il primo rendering. Ogni valore del componente letto dall'effetto va nell'array, e il linter ti dice quando ne manca uno.

Quando viene eseguita la funzione di cleanup di un effetto?

La funzione che restituisci da un effetto viene eseguita prima che l'effetto venga eseguito di nuovo con nuove dipendenze, e una volta quando il componente viene smontato. È lì che annulli ciò che l'effetto ha predisposto: cancelli un timer, rimuovi un listener, chiudi una connessione.

Clicca "Switch room" e guarda la console: prima viene eseguita la funzione di cleanup della vecchia stanza, poi l'effetto si connette a quella nuova. "Hide chat" esegue solo la funzione di cleanup. In sviluppo, StrictMode aggiunge al montaggio una connessione, disconnessione e connessione in più per verificare che la tua funzione di cleanup funzioni; l'anteprima gira come una build di produzione, quindi vedi solo la sequenza reale.

Perché il mio stato sembra vecchio dentro setInterval?

La callback dell'intervallo è una closure sul count del rendering che l'ha creata. Con un array delle dipendenze vuoto l'effetto non viene mai rieseguito, quindi la callback continua a leggere per sempre quel primo count.

broken arriva a 1 e si ferma, perché ogni tick calcola 0 + 1. fixed continua a contare, perché la funzione di aggiornamento riceve il valore più recente. Anche aggiungere broken all'array delle dipendenze funziona, al costo di cancellare e ricreare l'intervallo ogni secondo.

Cos'è il batching?

React raggruppa più aggiornamenti di stato in un unico rendering. Da React 18 questo vale ovunque: gestori di eventi, timeout, promise e listener di eventi nativi. Se ti serve che il DOM sia aggiornato subito dopo un aggiornamento, flushSync da react-dom ti fa uscire da questo comportamento, ma raramente ne avrai bisogno.

Il clic registra un solo render 1 1 1, non tre rendering. Prima di React 18, tre aggiornamenti di stato dentro un timeout significavano tre rendering.

Cosa registra questo codice? (ordine degli effetti)

Leggi il codice e scrivi le quattro righe che la console stamperà, in ordine, prima di guardarla.

Il rendering va dall'alto verso il basso: render App, poi render Child. Gli effetti vengono eseguiti dal basso verso l'alto, dopo che l'intero albero è stato applicato: effect Child, poi effect App. L'effetto di un genitore può contare sul fatto che gli effetti dei suoi figli siano già stati eseguiti.

Qual è la differenza tra useMemo e useCallback?

useMemo(() => compute(a, b), [a, b]) mette in cache il risultato di un calcolo. useCallback(fn, [deps]) mette in cache la funzione stessa, quindi equivale a useMemo(() => fn, [deps]). Entrambi aiutano solo quando qualcosa più in basso confronta per riferimento: un figlio con memo, o l'array delle dipendenze di un altro hook. Da React Compiler 1.0 (ottobre 2025) un passaggio di build può aggiungere questa memoizzazione automaticamente, ma la memoizzazione manuale funziona ancora e la vedrai comunque nella maggior parte delle codebase.

Cosa fa React.memo, e perché spesso ha bisogno di useCallback?

memo(Component) salta il nuovo render del componente quando le sue props sono uguali all'ultima volta, confrontate una per una con Object.is. Una funzione scritta in linea nel genitore è una nuova funzione a ogni rendering, quindi conta come prop cambiata e vanifica memo. useCallback mantiene la stessa funzione tra un rendering e l'altro.

Svuota la console e clicca "Re-render parent": compare solo render inline handler. L'altro figlio ha ricevuto la stessa funzione ed è stato saltato. Togli memo(...) attorno a Button ed entrambi registrano a ogni clic, il che mostra che useCallback da solo non fa nulla.

Cos'è il context, e quanto costa?

Il context passa un valore a ogni componente sotto un provider senza farlo passare attraverso le props: createContext, poi <ThemeContext value={theme}> in React 19 (o <ThemeContext.Provider>), e useContext(ThemeContext) per leggerlo. Il costo è che ogni componente che legge il context esegue un nuovo render quando il valore cambia, e memo non lo ferma. Mantienilo leggero dividendo valori non correlati in context separati, racchiudendo un valore oggetto in useMemo e tenendo lo stato che cambia rapidamente fuori dal context globale dell'app. Vedi useContext.

Cosa sono i ref, e quando usarne uno invece dello stato?

useRef(initial) restituisce un oggetto la cui proprietà current persiste tra un rendering e l'altro, e cambiarla non provoca un rendering. Usa un ref per i valori da cui lo schermo non dipende (l'id di un timer, il valore precedente, un flag) e per l'accesso al DOM (<input ref={inputRef}> e poi inputRef.current.focus()). Se il valore viene mostrato sullo schermo, va nello stato.

Cos'è il virtual DOM, e cos'è la reconciliation?

A ogni rendering React costruisce un nuovo albero di elementi e lo confronta con quello precedente; questo confronto è la reconciliation. Se il tipo di un elemento è cambiato (un div è diventato una section, o ProfileA è diventato ProfileB), React distrugge quel sottoalbero e il suo stato e ne costruisce uno nuovo. Se il tipo è lo stesso, mantiene il nodo DOM e aggiorna le props cambiate, e usa le key per abbinare i figli nelle liste. "Virtual DOM" è il nome popolare di quell'albero in memoria; la velocità deriva dal toccare solo ciò che è cambiato, non dal fatto che l'albero in sé sia veloce.

Cos'è un hook personalizzato?

Una funzione il cui nome inizia con use e che chiama altri hook, così puoi riutilizzare logica con stato tra i componenti: useOnlineStatus, useLocalStorage, useDebouncedValue. Ogni componente che lo chiama riceve il proprio stato indipendente; un hook personalizzato condivide la logica, non i dati. Vedi hook personalizzati.

Cosa fa StrictMode?

<StrictMode> attiva controlli aggiuntivi solo in sviluppo. Renderizza i componenti due volte per far emergere i rendering impuri, esegue gli effetti come setup, cleanup, setup una volta al montaggio per far emergere le funzioni di cleanup mancanti, fa lo stesso per i ref callback, e avvisa delle API deprecate. Nulla di tutto ciò avviene in una build di produzione, quindi un doppio log nella console in sviluppo è previsto e non è un bug.

Domande avanzate

Cosa registra questo codice? (render, layout effect, effect)

Un'altra previsione. Tre log, tre momenti diversi di un rendering.

L'ordine è render, poi useLayoutEffect, poi useEffect, anche se useEffect è scritto per primo. I layout effect vengono eseguiti dopo che React aggiorna il DOM ma prima che il browser disegni la pagina, ed è per questo che sono adatti a misurare un elemento; gli effetti normali vengono eseguiti più tardi, di solito dopo il disegno, e dovrebbero essere la scelta predefinita.

Cos'è un error boundary?

Un class component che intercetta gli errori generati durante il rendering dei suoi figli e mostra un fallback invece di smontare l'intera app. Ha bisogno di static getDerivedStateFromError (per passare al fallback) e di solito di componentDidCatch (per registrare l'errore). Non esiste ancora un equivalente con gli hook, quindi nelle codebase con function component i team scrivono una classe o usano il pacchetto react-error-boundary.

Clicca "Break it": il fallback sostituisce solo i figli del confine, il pulsante resta, e React segnala comunque l'errore intercettato nella console. I confini non intercettano gli errori nei gestori di eventi, nel codice asincrono come setTimeout, o nel confine stesso. Per quelli usi try/catch e imposti lo stato.

Cos'è un portal?

createPortal(children, domNode) da react-dom renderizza dei figli in un nodo DOM diverso, tipicamente document.body, mantenendoli nella stessa posizione dell'albero React. Modali, tooltip e notifiche lo usano per sfuggire all'overflow: hidden o al contesto di impilamento di un genitore. Il context funziona comunque attraverso un portal, e gli eventi risalgono attraverso l'albero React, quindi un clic dentro il portal raggiunge l'onClick del genitore anche se i nodi DOM sono altrove. Vedi portal.

Cosa sono Suspense e lazy?

lazy(() => import('./Chart')) carica il codice di un componente la prima volta che viene renderizzato, il che divide il tuo bundle. <Suspense fallback={<Spinner />}> mostra il fallback mentre qualcosa al suo interno è ancora in caricamento: codice lazy, o dati letti con use(promise) o con un framework che supporta Suspense. La posizione dei confini decide quali parti della pagina aspettano insieme.

import { lazy, Suspense } from 'react';

const Chart = lazy(() => import('./Chart.jsx'));

export default function Dashboard() {
    return (
        <Suspense fallback={<p>Loading chart...</p>}>
            <Chart />
        </Suspense>
    );
}

Cosa fa useTransition?

Segna un aggiornamento di stato come non urgente. const [isPending, startTransition] = useTransition() e startTransition(() => setTab('posts')) permettono a React di mantenere reattiva la schermata attuale e di interrompere il rendering lento se arriva un aggiornamento più urgente, come un tasto premuto. isPending ti dice di mostrare un'indicazione. In React 19 la funzione che passi può essere async, ed è ciò che React chiama action. Non usarlo per aggiornare il valore stesso di un input di testo; quell'aggiornamento deve essere urgente.

Cosa sono i React Server Component?

Componenti che vengono eseguiti solo sul server (o al momento della build) e inviano al browser il loro risultato renderizzato, mai il loro codice. Possono essere async e leggere direttamente un database o il file system, ma non possono usare stato, effetti o API del browser. Un file contrassegnato con 'use client' avvia un confine client dove vivono i componenti interattivi, e 'use server' contrassegna le server function che il codice client può chiamare. Li usi tramite un framework come Next.js con l'App Router; le semplici app Vite non hanno un server per eseguirli.

Cosa è cambiato in React 19?

  • Action: funzioni async nelle transizioni, con lo stato di attesa gestito per te. Un <form action={fn}> chiama fn con i FormData del form.
  • Nuovi hook: useActionState per il risultato e lo stato di attesa di un form, useOptimistic per la UI ottimistica, e useFormStatus in react-dom.
  • use: legge una promise (sospendendosi finché non si risolve) o un context, e a differenza degli altri hook può essere chiamato dentro una condizione.
  • ref come prop: i function component ricevono ref come qualsiasi altra prop, quindi forwardRef non serve più per il codice nuovo. I ref callback possono restituire una funzione di cleanup.
  • <Context> come provider, più i tag <title> e <meta> che vengono spostati nell'head del documento.
  • Rimozioni: ReactDOM.render, i ref stringa, il context legacy e defaultProps sui function component (usa i parametri predefiniti).
// React 19: ref is a normal prop
function TextInput({ ref, ...props }) {
    return <input ref={ref} {...props} />;
}

La pagina su React 19 ha esempi eseguibili di ciascuno.

Come si testano i componenti React?

Con React Testing Library e un test runner come Vitest o Jest. Renderizzi il componente, trovi gli elementi come farebbe un utente (per ruolo, etichetta o testo), interagisci con user-event e fai asserzioni su ciò che è visibile, non sullo stato interno. Così i test restano validi attraverso i refactoring.

import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import Counter from './Counter';

test('counts clicks', async () => {
    const user = userEvent.setup();
    render(<Counter />);
    await user.click(screen.getByRole('button', { name: /clicked 0 times/i }));
    expect(screen.getByRole('button')).toHaveTextContent('Clicked 1 times');
});

toHaveTextContent arriva da @testing-library/jest-dom. Per flussi completi tra più pagine, i team aggiungono sopra Playwright o Cypress.

Come si trova e si risolve un problema di prestazioni?

Prima misura. Apri la scheda Profiler di React DevTools, registra l'interazione lenta e leggi il flame chart: mostra quali componenti si sono renderizzati, quanto tempo ha richiesto ciascuno e (con l'impostazione "record why each component rendered") perché. Le soluzioni tipiche, nell'ordine in cui provarle: sposta lo stato verso il basso così meno componenti dipendono da esso, passa i sottoalberi lenti come children, memorizza la parte costosa con memo, useMemo e useCallback, virtualizza le liste lunghe e rimanda gli aggiornamenti pesanti con useTransition o useDeferredValue. Fai il profiling in una build di produzione o di profiling; le build di sviluppo sono più lente ed esagerano i tempi di rendering.

Perché un componente dovrebbe essere puro?

Date le stesse props, lo stesso stato e lo stesso context, un componente dovrebbe restituire lo stesso JSX e non cambiare nulla al di fuori di sé durante il rendering. React può renderizzare un componente più di una volta, fuori ordine, o buttare via un rendering (transizioni, Suspense, StrictMode), quindi gli effetti collaterali nel corpo, come modificare una variabile o inviare una richiesta, vengono eseguiti un numero imprevedibile di volte. Gli effetti collaterali vanno prima di tutto nei gestori di eventi, e negli effetti quando nessun evento li ha causati.

Quando non dovresti usare un effetto?

Quando il valore può essere calcolato durante il rendering (liste filtrate, nomi completi, totali), quando il lavoro è causato da un'azione dell'utente (mettilo nel gestore di eventi), e quando vuoi azzerare lo stato al cambio di una prop (usa una key). Gli effetti servono a sincronizzarsi con qualcosa al di fuori di React: una connessione di rete, un'API del browser, un widget di terze parti. Le catene di effetti che impostano lo stato sono una fonte comune di rendering in più e di bug.

Domande frequenti

Cos'è React?

React è una libreria JavaScript per costruire interfacce utente a partire da componenti. Descrivi come deve apparire lo schermo per i dati attuali, e React aggiorna il DOM reale quando quei dati cambiano.

Qual è la differenza tra stato e props?

Le props sono input che un genitore passa a un componente, e il componente le tratta come di sola lettura. Lo stato sono dati che un componente possiede e cambia nel tempo con un setter, il che lo fa renderizzare di nuovo da React.

Cosa sono gli hook in React?

Gli hook sono funzioni il cui nome inizia con use che permettono a un function component di usare le funzionalità di React: useState per lo stato, useEffect per gli effetti collaterali, useContext per il context, useRef per valori che non provocano rendering, e altri.

Cos'è il virtual DOM?

È il nome della descrizione in memoria della UI che React tiene. A ogni rendering React costruisce una nuova descrizione, la confronta con quella precedente e applica al DOM reale solo le differenze. Quel confronto si chiama reconciliation.

Perché le key contano nelle liste React?

Una key dice a React quale voce di una lista è quale tra un rendering e l'altro. Con key stabili (come un id) React mantiene lo stato e il nodo DOM di ogni voce collegati ai dati giusti quando le voci vengono aggiunte, rimosse o riordinate. Usare l'indice dell'array rompe questo meccanismo quando l'ordine cambia.

Cos'è JSX?

JSX è un'estensione della sintassi che ti permette di scrivere markup simile all'HTML in JavaScript. Un compilatore trasforma ogni tag in una chiamata di funzione che crea un elemento React, quindi <h1>Hi</h1> diventa un semplice oggetto che descrive un h1.

Illustrazione dei linguaggi di programmazione di Coddy

Impara a programmare con Coddy

INIZIA