React v18.0

Nota bene

Questa pagina è stata tradotta automaticamente e supervisionata da un maintainer. Un’ulteriore revisione da parte della community sarebbe comunque utile. Migliora questa traduzione.

29 marzo 2022 di The React Team


React 18 è ora disponibile su npm! Nel nostro ultimo post, abbiamo condiviso istruzioni passo passo per passare la tua app a React 18. In questo post, daremo una panoramica delle novità di React 18 e di cosa significano per il futuro.


La nostra ultima versione major include miglioramenti out-of-the-box come il raggruppamento automatico, nuove API come startTransition e server-side rendering in streaming con supporto per Suspense.

Molte delle funzionalità in React 18 sono costruite sopra il nostro nuovo renderer concorrente, un cambiamento dietro le quinte che sblocca potenti nuove capability. Concurrent React è opt-in — è abilitato solo quando usi una funzionalità concorrente — ma pensiamo che avrà un grande impatto sul modo in cui le persone costruiscono applicazioni.

Abbiamo passato anni a ricercare e sviluppare il supporto per la concorrenza in React, e abbiamo avuto cura di fornire un percorso di adozione graduale per gli utenti esistenti. Lo scorso estate, abbiamo formato il React 18 Working Group per raccogliere feedback dagli esperti della community e garantire un’esperienza di upgrade fluida per l’intero ecosistema React.

Nel caso te lo fossi perso, abbiamo condiviso gran parte di questa visione alla React Conf 2021:

Di seguito una panoramica completa di cosa aspettarsi in questo rilascio, a partire dal Concurrent Rendering.

Nota bene

Per gli utenti React Native, React 18 sarà incluso in React Native con la New React Native Architecture. Per maggiori informazioni, consulta la keynote di React Conf qui.

Cos’è Concurrent React?

L’aggiunta più importante in React 18 è qualcosa che speriamo tu non debba mai pensare: la concorrenza. Pensiamo che questo sia in larga parte vero per gli sviluppatori di applicazioni, anche se la storia potrebbe essere un po’ più complicata per i maintainer di librerie.

La concorrenza non è una funzionalità, di per sé. È un nuovo meccanismo dietro le quinte che consente a React di preparare più versioni della tua UI contemporaneamente. Puoi pensare alla concorrenza come a un dettaglio implementativo — è preziosa per le funzionalità che sblocca. React usa tecniche sofisticate nella sua implementazione interna, come code di priorità e buffering multiplo. Ma non vedrai quei concetti nelle nostre API pubbliche.

Quando progettiamo le API, cerchiamo di nascondere i dettagli implementativi agli sviluppatori. Come sviluppatore React, ti concentri su cosa vuoi che sia l’esperienza utente, e React gestisce come consegnarla. Quindi non ci aspettiamo che gli sviluppatori React sappiano come funziona la concorrenza sotto il cofano.

Tuttavia, Concurrent React è più importante di un tipico dettaglio implementativo — è un aggiornamento fondamentale al modello di rendering core di React. Quindi, anche se non è fondamentale sapere come funziona la concorrenza, potrebbe valere la pena saperne cos’è a livello generale.

Una proprietà chiave di Concurrent React è che la renderizzazione è interrompibile. Quando passi per la prima volta a React 18, prima di aggiungere funzionalità concorrenti, gli aggiornamenti vengono renderizzati come nelle versioni precedenti di React — in una singola transazione sincrona e ininterrotta. Con la renderizzazione sincrona, una volta che un aggiornamento inizia a renderizzare, nulla può interromperlo finché l’utente non vede il risultato sullo schermo.

In una renderizzazione concorrente, non è sempre così. React può iniziare a renderizzare un aggiornamento, metterlo in pausa a metà, poi continuare più tardi. Può persino abbandonare del tutto una renderizzazione in corso. React garantisce che l’UI apparirà consistente anche se una renderizzazione viene interrotta. Per farlo, attende di eseguire mutazioni DOM fino alla fine, una volta che l’intero albero è stato valutato. Con questa capability, React può preparare nuove schermate in background senza bloccare il main thread. Questo significa che l’UI può rispondere immediatamente all’input dell’utente anche se è nel mezzo di un grande task di renderizzazione, creando un’esperienza utente fluida.

Un altro esempio è lo state riutilizzabile. Concurrent React può rimuovere sezioni dell’UI dallo schermo, poi riaggiungerle più tardi riutilizzando lo state precedente. Ad esempio, quando un utente passa a un’altra schermata e torna indietro, React dovrebbe poter ripristinare la schermata precedente nello stesso state in cui era prima. In una prossima minor, stiamo pianificando di aggiungere un nuovo componente chiamato <Offscreen> che implementa questo pattern. Allo stesso modo, potrai usare Offscreen per preparare nuova UI in background così che sia pronta prima che l’utente la riveli.

Il concurrent rendering è un potente nuovo strumento in React e la maggior parte delle nostre nuove funzionalità è costruita per sfruttarlo, inclusi Suspense, le transizioni e il server rendering in streaming. Ma React 18 è solo l’inizio di ciò che intendiamo costruire su questa nuova fondazione.

Adozione graduale delle funzionalità concorrenti

Tecnicamente, il concurrent rendering è un breaking change. Poiché il concurrent rendering è interrompibile, i componenti si comportano leggermente diversamente quando è abilitato.

Nei nostri test, abbiamo aggiornato migliaia di componenti a React 18. Abbiamo scoperto che quasi tutti i componenti esistenti “funzionano semplicemente” con il concurrent rendering, senza modifiche. Tuttavia, alcuni potrebbero richiedere uno sforzo di migrazione aggiuntivo. Anche se i cambiamenti sono di solito piccoli, avrai comunque la possibilità di farli al tuo ritmo. Il nuovo comportamento di rendering in React 18 è abilitato solo nelle parti della tua app che usano le nuove funzionalità.

La strategia complessiva di upgrade è far girare la tua applicazione su React 18 senza rompere il codice esistente. Poi puoi iniziare gradualmente ad aggiungere funzionalità concorrenti al tuo ritmo. Puoi usare <StrictMode> per aiutare a far emergere bug legati alla concorrenza durante lo sviluppo. Strict Mode non influisce sul comportamento in produzione, ma durante lo sviluppo registrerà warning extra e invocherà due volte funzioni che devono essere idempotenti. Non catturerà tutto, ma è efficace nel prevenire i tipi di errori più comuni.

Dopo l’upgrade a React 18, potrai iniziare a usare le funzionalità concorrenti immediatamente. Ad esempio, puoi usare startTransition per navigare tra schermate senza bloccare l’input dell’utente. Oppure useDeferredValue per limitare ri-renderizzazioni costose.

Tuttavia, a lungo termine, ci aspettiamo che il modo principale in cui aggiungerai concorrenza alla tua app sia usando una libreria o un framework abilitati alla concorrenza. Nella maggior parte dei casi, non interagirai direttamente con le API concorrenti. Ad esempio, invece che gli sviluppatori chiamino startTransition ogni volta che navigano a una nuova schermata, le librerie di routing avvolgeranno automaticamente le navigazioni in startTransition.

Potrebbe volerci del tempo perché le librerie si aggiornino per essere compatibili con la concorrenza. Abbiamo fornito nuove API per rendere più facile per le librerie sfruttare le funzionalità concorrenti. Nel frattempo, sii paziente con i maintainer mentre lavoriamo per migrare gradualmente l’ecosistema React.

Per maggiori informazioni, consulta il nostro post precedente: Come passare a React 18.

Suspense nei framework per i dati

In React 18, puoi iniziare a usare Suspense per il data fetching in framework opinionated come Relay, Next.js, Hydrogen o Remix. Il data fetching ad hoc con Suspense è tecnicamente possibile, ma non è ancora consigliato come strategia generale.

In futuro, potremmo esporre primitivi aggiuntivi che rendano più facile accedere ai tuoi dati con Suspense, forse senza l’uso di un framework opinionated. Tuttavia, Suspense funziona meglio quando è profondamente integrato nell’architettura della tua applicazione: il tuo router, il tuo data layer e il tuo ambiente di server rendering. Quindi, anche a lungo termine, ci aspettiamo che librerie e framework giochino un ruolo cruciale nell’ecosistema React.

Come nelle versioni precedenti di React, puoi anche usare Suspense per il code splitting sul client con React.lazy. Ma la nostra visione per Suspense è sempre stata molto più del semplice caricamento del codice — l’obiettivo è estendere il supporto per Suspense così che, alla fine, lo stesso fallback Suspense dichiarativo possa gestire qualsiasi operazione asincrona (caricamento codice, dati, immagini, ecc.).

I Server Components sono ancora in sviluppo

I Server Components sono una funzionalità in arrivo che consente agli sviluppatori di costruire app che coprono server e client, combinando la ricca interattività delle app client-side con le prestazioni migliorate del tradizionale server rendering. I Server Components non sono intrinsecamente accoppiati a Concurrent React, ma sono progettati per funzionare al meglio con funzionalità concorrenti come Suspense e server rendering in streaming.

I Server Components sono ancora sperimentali, ma ci aspettiamo di rilasciare una versione iniziale in una minor 18.x. Nel frattempo, stiamo lavorando con framework come Next.js, Hydrogen e Remix per far avanzare la proposta e prepararla per un’adozione diffusa.

Novità in React 18

Nuova funzionalità: raggruppamento automatico

Il raggruppamento è quando React raggruppa più aggiornamenti di state in una singola ri-renderizzazione per prestazioni migliori. Senza raggruppamento automatico, raggruppavamo gli aggiornamenti solo all’interno dei gestori di eventi React. Gli aggiornamenti all’interno di promise, setTimeout, gestori di eventi nativi o qualsiasi altro evento non venivano raggruppati in React per impostazione predefinita. Con il raggruppamento automatico, questi aggiornamenti verranno raggruppati automaticamente:

// Before: only React events were batched.
setTimeout(() => {
setCount(c => c + 1);
setFlag(f => !f);
// React will render twice, once for each state update (no batching)
}, 1000);

// After: updates inside of timeouts, promises,
// native event handlers or any other event are batched.
setTimeout(() => {
setCount(c => c + 1);
setFlag(f => !f);
// React will only re-render once at the end (that's batching!)
}, 1000);

Per maggiori informazioni, consulta questo post su Automatic batching for fewer renders in React 18.

Nuova funzionalità: Transizioni

Una transizione è un nuovo concetto in React per distinguere tra aggiornamenti urgenti e non urgenti.

  • Aggiornamenti urgenti riflettono interazione diretta, come digitare, cliccare, premere e così via.
  • Aggiornamenti di transizione fanno passare l’UI da una vista a un’altra.

Gli aggiornamenti urgenti come digitare, cliccare o premere hanno bisogno di risposta immediata per corrispondere alle nostre intuizioni su come si comportano gli oggetti fisici. Altrimenti sembrano “sbagliati”. Tuttavia, le transizioni sono diverse perché l’utente non si aspetta di vedere ogni valore intermedio sullo schermo.

Ad esempio, quando selezioni un filtro in un dropdown, ti aspetti che il pulsante del filtro risponda immediatamente quando clicchi. Tuttavia, i risultati effettivi possono transitare separatamente. Un piccolo ritardo sarebbe impercettibile e spesso atteso. E se cambi di nuovo il filtro prima che i risultati finiscano di renderizzare, ti interessa vedere solo gli ultimi risultati.

Tipicamente, per la migliore esperienza utente, un singolo input dell’utente dovrebbe produrre sia un aggiornamento urgente che uno non urgente. Puoi usare l’API startTransition all’interno di un evento di input per informare React quali aggiornamenti sono urgenti e quali sono “transizioni”:

import { startTransition } from 'react';

// Urgent: Show what was typed
setInputValue(input);

// Mark any state updates inside as transitions
startTransition(() => {
// Transition: Show the results
setSearchQuery(input);
});

Gli aggiornamenti avvolti in startTransition sono gestiti come non urgenti e verranno interrotti se arrivano aggiornamenti più urgenti come click o pressioni di tasti. Se una transizione viene interrotta dall’utente (ad esempio, digitando più caratteri di fila), React scarterà il lavoro di renderizzazione stale non completato e renderizzerà solo l’ultimo aggiornamento.

  • useTransition: un Hook per avviare transizioni, incluso un valore per tracciare lo state pending.
  • startTransition: un metodo per avviare transizioni quando l’Hook non può essere usato.

Le transizioni opt-in al concurrent rendering, che consente all’aggiornamento di essere interrotto. Se il contenuto si ri-sospende, le transizioni dicono anche a React di continuare a mostrare il contenuto attuale mentre renderizza il contenuto della transizione in background (consulta la Suspense RFC per maggiori informazioni).

Consulta la documentazione sulle transizioni qui.

Nuove funzionalità Suspense

Suspense ti consente di specificare dichiarativamente lo state di caricamento per una parte dell’albero dei componenti se non è ancora pronta per essere visualizzata:

<Suspense fallback={<Spinner />}>
<Comments />
</Suspense>

Suspense rende lo “state di caricamento dell’UI” un concetto dichiarativo di prima classe nel modello di programmazione React. Questo ci consente di costruire funzionalità di livello superiore sopra di esso.

Abbiamo introdotto una versione limitata di Suspense diversi anni fa. Tuttavia, l’unico caso d’uso supportato era il code splitting con React.lazy, e non era supportato affatto quando si renderizzava sul server.

In React 18, abbiamo aggiunto il supporto per Suspense sul server ed espanso le sue capability usando le funzionalità di concurrent rendering.

Suspense in React 18 funziona meglio quando combinato con l’API delle transizioni. Se sospendi durante una transizione, React impedirà al contenuto già visibile di essere sostituito da un fallback. Invece, React ritarderà la renderizzazione finché non sono stati caricati abbastanza dati per evitare uno state di caricamento scadente.

Per maggiori informazioni, consulta la RFC Suspense in React 18.

Nuove API di client e server rendering

In questo rilascio abbiamo colto l’occasione per ridisegnare le API che esponiamo per la renderizzazione su client e server. Questi cambiamenti consentono agli utenti di continuare a usare le vecchie API in modalità React 17 mentre passano alle nuove API in React 18.

React DOM Client

Queste nuove API sono ora esportate da react-dom/client:

  • createRoot: nuovo metodo per creare una root per render o unmount. Usalo al posto di ReactDOM.render. Le nuove funzionalità in React 18 non funzionano senza di esso.
  • hydrateRoot: nuovo metodo per idratare un’applicazione renderizzata sul server. Usalo al posto di ReactDOM.hydrate insieme alle nuove API React DOM Server. Le nuove funzionalità in React 18 non funzionano senza di esso.

Sia createRoot che hydrateRoot accettano una nuova opzione chiamata onRecoverableError nel caso tu voglia essere notificato quando React recupera da errori durante la renderizzazione o l’hydration per il logging. Per impostazione predefinita, React userà reportError, o console.error nei browser più vecchi.

Consulta la documentazione di React DOM Client qui.

React DOM Server

Queste nuove API sono ora esportate da react-dom/server e hanno supporto completo per lo streaming di Suspense sul server:

  • renderToPipeableStream: per lo streaming in ambienti Node.
  • renderToReadableStream: per ambienti edge runtime moderni, come Deno e Cloudflare workers.

Il metodo esistente renderToString continua a funzionare ma è sconsigliato.

Consulta la documentazione di React DOM Server qui.

Nuovi comportamenti di Strict Mode

In futuro, vorremmo aggiungere una funzionalità che consente a React di aggiungere e rimuovere sezioni dell’UI preservando lo state. Ad esempio, quando un utente passa a un’altra schermata e torna indietro, React dovrebbe poter mostrare immediatamente la schermata precedente. Per farlo, React smonterebbe e rimonterebbe alberi usando lo stesso component state di prima.

Questa funzionalità darà alle app React prestazioni migliori out-of-the-box, ma richiede che i componenti siano resilienti agli Effetti montati e distrutti più volte. La maggior parte degli Effetti funzionerà senza modifiche, ma alcuni Effetti presuppongono di essere montati o distrutti una sola volta.

Per aiutare a far emergere questi problemi, React 18 introduce un nuovo controllo solo per development in Strict Mode. Questo nuovo controllo smonterà e rimonterà automaticamente ogni componente, ogni volta che un componente viene montato per la prima volta, ripristinando lo state precedente al secondo mount.

Prima di questo cambiamento, React montava il componente e creava gli Effetti:

* React mounts the component.
* Layout effects are created.
* Effects are created.

Con Strict Mode in React 18, React simulerà lo smontaggio e il rimontaggio del componente in modalità development:

* React mounts the component.
* Layout effects are created.
* Effects are created.
* React simulates unmounting the component.
* Layout effects are destroyed.
* Effects are destroyed.
* React simulates mounting the component with the previous state.
* Layout effects are created.
* Effects are created.

Consulta la documentazione per garantire state riutilizzabile qui.

Nuovi Hooks

useId

useId è un nuovo Hook per generare ID univoci sia sul client che sul server, evitando mismatch di hydration. È principalmente utile per librerie di componenti che si integrano con API di accessibilità che richiedono ID univoci. Risolve un problema che esiste già in React 17 e versioni precedenti, ma è ancora più importante in React 18 per come il nuovo streaming server renderer consegna HTML fuori ordine. Consulta la documentazione qui.

Nota

useId non serve per generare key in una lista. Le key dovrebbero essere generate dai tuoi dati.

useTransition

useTransition e startTransition ti consentono di contrassegnare alcuni aggiornamenti di state come non urgenti. Altri aggiornamenti di state sono considerati urgenti per impostazione predefinita. React consentirà agli aggiornamenti di state urgenti (ad esempio, aggiornare un input di testo) di interrompere aggiornamenti di state non urgenti (ad esempio, renderizzare una lista di risultati di ricerca). Consulta la documentazione qui.

useDeferredValue

useDeferredValue ti consente di rimandare la ri-renderizzazione di una parte non urgente dell’albero. È simile al debouncing, ma ha alcuni vantaggi rispetto ad esso. Non c’è un ritardo temporale fisso, quindi React tenterà la renderizzazione differita subito dopo che la prima renderizzazione è riflessa sullo schermo. La renderizzazione differita è interrompibile e non blocca l’input dell’utente. Consulta la documentazione qui.

useSyncExternalStore

useSyncExternalStore è un nuovo Hook che consente agli store esterni di supportare letture concorrenti forzando gli aggiornamenti allo store a essere sincroni. Elimina la necessità di useEffect quando si implementano sottoscrizioni a sorgenti dati esterne ed è consigliato per qualsiasi libreria che si integra con state esterno a React. Consulta la documentazione qui.

Nota

useSyncExternalStore è pensato per essere usato dalle librerie, non dal codice applicativo.

useInsertionEffect

useInsertionEffect è un nuovo Hook che consente alle librerie CSS-in-JS di affrontare problemi di prestazioni legati all’iniezione di stili durante la renderizzazione. A meno che tu non abbia già costruito una libreria CSS-in-JS, non ci aspettiamo che tu la usi mai. Questo Hook viene eseguito dopo la mutazione del DOM, ma prima che gli Effetti di layout leggano il nuovo layout. Risolve un problema che esiste già in React 17 e versioni precedenti, ma è ancora più importante in React 18 perché React cede il controllo al browser durante il concurrent rendering, dandogli la possibilità di ricalcolare il layout. Consulta la documentazione qui.

Nota

useInsertionEffect è pensato per essere usato dalle librerie, non dal codice applicativo.

Come effettuare l’upgrade

Consulta Come passare a React 18 per istruzioni passo passo e l’elenco completo dei breaking change e dei cambiamenti rilevanti.

Changelog

React

React DOM

React DOM Server

React DOM Test Utils

  • Throw when act is used in production. (#21686 by @acdlite)
  • Support disabling spurious act warnings with global.IS_REACT_ACT_ENVIRONMENT. (#22561 by @acdlite)
  • Expand act warning to cover all APIs that might schedule React work. (#22607 by @acdlite)
  • Make act batch updates. (#21797 by @acdlite)
  • Remove warning for dangling passive effects. (#22609 by @acdlite)

React Refresh

Server Components (Experimental)