diff --git a/src/content/reference/react-dom/components/img.md b/src/content/reference/react-dom/components/img.md index 992b2e0ad..ec268975a 100644 --- a/src/content/reference/react-dom/components/img.md +++ b/src/content/reference/react-dom/components/img.md @@ -56,9 +56,15 @@ Per visualizzare un'immagine, renderizza il [componente browser integrato ` #### Caveats {/*caveats*/} +<<<<<<< HEAD * Non passare una stringa vuota a `src`: potrebbe indurre il browser a richiedere di nuovo la pagina corrente. React mostra un avviso in sviluppo e omette l'attributo. Per non visualizzare alcuna immagine, ometti `` o passa `null` a `src`. * `` non può avere children né usare `dangerouslySetInnerHTML`. React solleva un errore se passi una delle due cose. * `fetchPriority="low"` non impedisce a React di attendere che l'immagine venga caricata e decodificata durante un aggiornamento View Transition renderizzato lato client. Usa `loading="lazy"` o un gestore `onLoad` per rinunciare a questo comportamento. +======= +* Do not pass an empty string to `src`. It may cause the browser to request the current page again. React warns in development and omits the attribute. To render no image, omit the `` or pass `null` to `src`. +* `` cannot have children or use `dangerouslySetInnerHTML`. React throws an error if you pass either. +* `fetchPriority="low"` does not stop React from waiting for the image to load during a client-rendered View Transition update. Use `loading="lazy"` or an `onLoad` handler to opt out of that behavior. +>>>>>>> 046f17d04295ba047bb5739026b4ac3110f17028 --- @@ -132,6 +138,7 @@ Per creare un hint di preload esplicito, chiama [`preload`](/reference/react-dom ### Attendere un'immagine durante una View Transition {/*waiting-for-an-image-during-a-view-transition*/} +<<<<<<< HEAD Durante un aggiornamento [``](/reference/react/ViewTransition) renderizzato lato client, React potrebbe attendere che un'immagine si carichi e venga decodificata prima di avviare l'animazione. Questo si applica quando viene renderizzato un nuovo `` con un `src` non vuoto, o quando `src` o `srcSet` di un'immagine esistente cambia. L'immagine deve trovarsi nel sottoalbero del `` e non deve avere `loading="lazy"` né un gestore `onLoad`. React non attende le immagini durante gli aggiornamenti sincroni. Quando un boundary Suspense rivela contenuto in streaming all'interno di un ``, React potrebbe anche attendere le immagini visibili con un `src` non vuoto che non hanno `loading="lazy"`. React smette di attendere dopo un timeout, così che un'immagine lenta non blocchi l'aggiornamento all'infinito. @@ -139,18 +146,28 @@ Quando un boundary Suspense rivela contenuto in streaming all'interno di un `` e mostra un placeholder del profilo finché il ritratto non si è caricato. Per confronto, il secondo pulsante inserisce la stessa card direttamente nel DOM. La card appare immediatamente, e il browser visualizza l'immagine dopo che si è caricata: +======= +During a [``](/reference/react/ViewTransition) update, React waits up to 500 ms for visible images to load before starting the animation. This includes newly rendered `` elements and existing images whose `src` or `srcSet` changes. Setting `loading="lazy"` or adding an `onLoad` handler opts an image out. + +Compare how the same image appears when a Suspense boundary reveals its content inside and outside a ``: +>>>>>>> 046f17d04295ba047bb5739026b4ac3110f17028 ```js -import { ViewTransition, Suspense, useState, startTransition } from 'react'; -import { freshImageUrl } from './image.js'; -import VanillaProfile from './VanillaProfile.js'; - -function Profile({ src }) { +import { + ViewTransition, + Suspense, + use, + useState, +} from 'react'; +import { fetchImageSrc } from './image.js'; + +function Profile({ cacheKey }) { + const src = use(fetchImageSrc(cacheKey)); return (
- Jack Pope +

Jack Pope

); @@ -166,9 +183,13 @@ function ProfilePlaceholder() { } export default function App() { - const [src, setSrc] = useState(null); + const [showWithTransition, setShowWithTransition] = + useState(false); + const [showWithoutTransition, setShowWithoutTransition] = + useState(false); return ( <> +<<<<<<< HEAD - {src && ( + {showWithTransition && ( }> - + )}
+<<<<<<< HEAD ); @@ -207,15 +233,42 @@ export default function VanillaProfile() { <>
+======= + + {showWithoutTransition && ( + }> + + + )} +>>>>>>> 046f17d04295ba047bb5739026b4ac3110f17028 ); } ``` ```js src/image.js hidden +<<<<<<< HEAD // Aggiungi un parametro univoco così l'immagine non finisce in cache // e ogni esecuzione mostra lo stato di caricamento. export function freshImageUrl() { +======= +// Normally, the caching logic would be inside a framework. +const cache = new Map(); + +export function fetchImageSrc(cacheKey) { + if (!cache.has(cacheKey)) { + cache.set(cacheKey, loadImageSrc()); + } + return cache.get(cacheKey); +} + +async function loadImageSrc() { + // Delay the response so the Suspense fallback is visible. + await new Promise(resolve => setTimeout(resolve, 1000)); + // Add a unique parameter so the image isn't cached. +>>>>>>> 046f17d04295ba047bb5739026b4ac3110f17028 return 'https://react.dev/images/team/jack-pope.jpg?t=' + Date.now(); } ``` @@ -262,3 +315,5 @@ hr { ``` + +With ``, React keeps the skeleton visible for up to 500 ms while the image loads, so the card can be revealed with its image already in place. Without ``, Suspense stops showing the skeleton as soon as the Promise resolves. If the image is still loading, the card appears first and the image pops in afterward. diff --git a/src/content/reference/react/Suspense.md b/src/content/reference/react/Suspense.md index 23367f8de..96f999dfc 100644 --- a/src/content/reference/react/Suspense.md +++ b/src/content/reference/react/Suspense.md @@ -50,6 +50,7 @@ Questa pagina è stata tradotta automaticamente e supervisionata da un maintaine Un boundary Suspense attende che il suo contenuto sia pronto prima di rivelarlo. Qualsiasi elemento tra i seguenti impedisce a un boundary di rivelare il suo contenuto: +<<<<<<< HEAD - Lazy-loading del codice del componente con [`lazy`](/reference/react/lazy). - Lettura di una Promise con [`use`](/reference/react/use), inclusi dati in streaming da [componenti Server](/reference/rsc/server-components) o caricati tramite un [framework abilitato a Suspense](#suspense-enabled-frameworks). - Caricamento di un foglio di stile renderizzato con [`` e una prop `precedence`.](/reference/react-dom/components/link#special-rendering-behavior) React blocca il boundary finché il foglio di stile non è caricato, fino a un timeout. [Vedi un esempio sotto.](#waiting-for-a-stylesheet-to-load) @@ -57,6 +58,15 @@ Un boundary Suspense attende che il suo contenuto sia pronto prima di rivelarlo. - Caricamento dei font. Suspense non attende i font per impostazione predefinita, ma un aggiornamento con [``](/reference/react/ViewTransition) attende il caricamento dei nuovi font, fino a un timeout, così il testo non lampeggia con un font di fallback. [Vedi un esempio sotto.](#waiting-for-a-font-to-load) - Caricamento delle immagini. Suspense non attende le immagini per impostazione predefinita, ma durante un aggiornamento con [``](/reference/react/ViewTransition), React blocca il boundary finché l'immagine non è caricata, fino a un timeout. Aggiungere un gestore `onLoad` esclude una specifica immagine da questo comportamento. [Vedi un esempio sotto.](#waiting-for-an-image-to-load) - Esecuzione di lavoro di renderizzazione CPU-bound dentro un boundary [``](#props). +======= +- Lazy-loading component code with [`lazy`](/reference/react/lazy). +- Reading a Promise with [`use`](/reference/react/use), including data streamed from [Server Components](/reference/rsc/server-components) or loaded through a [Suspense-enabled framework](#suspense-enabled-frameworks). +- Loading a stylesheet rendered with [`` and a `precedence` prop.](/reference/react-dom/components/link#special-rendering-behavior) React blocks the boundary until the stylesheet loads, up to a timeout. [See an example below.](#waiting-for-a-stylesheet-to-load) +- Waiting for a large boundary's HTML to arrive during streaming server rendering. Sending HTML takes time, so a boundary with enough content activates even when nothing in it suspends. React reveals the content as the HTML arrives. +- Loading fonts. Suspense doesn't wait for fonts by default, but when a [``](/reference/react/ViewTransition) animates a boundary's reveal, React waits up to 500 ms for new fonts to load so text doesn't flash with a fallback font. [See an example below.](#waiting-for-a-font-to-load) +- Loading images. Suspense doesn't wait for images by default, but when a [``](/reference/react/ViewTransition) animates a boundary's reveal, React waits up to 500 ms for visible images to load before starting the animation. Setting `loading="lazy"` or adding an `onLoad` handler opts a specific image out. [See an example below.](#waiting-for-an-image-to-load) +- Performing CPU-bound render work inside a [``](#props) boundary. +>>>>>>> 046f17d04295ba047bb5739026b4ac3110f17028 @@ -2908,52 +2918,65 @@ Dove posizioni il `` rispetto al boundary determina se fallback ### Attendere il caricamento di un font {/*waiting-for-a-font-to-load*/} +<<<<<<< HEAD Quando un [``](/reference/react/ViewTransition) anima la rivelazione di un boundary Suspense, React attende i nuovi font introdotti dal contenuto, fino a un timeout, così il testo non lampeggia con un font di fallback. Questo avviene solo durante un aggiornamento con ``. Nell'esempio sotto, il boundary Suspense è avvolto in un `` e il componente `Quote` va in sospensione mentre i suoi dati si caricano. Renderizzare la citazione avvia il download del font. React mantiene visibile il fallback finché il font non è caricato, così la citazione appare già nel suo font. +======= +When a [``](/reference/react/ViewTransition) animates a Suspense boundary's reveal, React waits up to 500 ms for new fonts the content introduces so the text doesn't flash with a fallback font. This only happens during a `` update. + +In the example below, the Suspense boundary is wrapped in a ``, and the `Quote` component suspends while its data loads. Rendering the quote loads a stylesheet that introduces the font. React keeps the fallback visible while the stylesheet and font load. If the font loads within the 500 ms limit, the quote appears already in its font. +>>>>>>> 046f17d04295ba047bb5739026b4ac3110f17028 A titolo di confronto, il secondo pulsante esegue lo stesso aggiornamento senza React. Nulla attende il font, quindi il testo appare prima in un font di fallback e poi cambia: ```js -import { ViewTransition, Suspense, use, useState, startTransition } from 'react'; +import { + ViewTransition, + Suspense, + use, + useState, + startTransition, +} from 'react'; import { fetchQuote } from './data.js'; -import { freshFontUrl } from './font.js'; +import { + freshFontUrl, + freshStylesheetUrl, +} from './font.js'; import VanillaQuote from './VanillaQuote.js'; -function Quote({ fontSrc }) { +function Quote({ stylesheet }) { const quote = use(fetchQuote()); return ( <> - +

{quote}

); } export default function App() { - const [fontSrc, setFontSrc] = useState(null); + const [stylesheet, setStylesheet] = useState(null); return ( <> - {fontSrc && ( + {stylesheet && ( ⌛ Loading quote...

}> - +
)} @@ -2974,7 +2997,7 @@ export default function VanillaQuote() { const style = document.createElement('style'); style.textContent = `@font-face { font-family: 'VanillaFancy'; - src: url(${freshFontUrl()}) format('truetype'); + src: url(${freshFontUrl()}) format('woff2'); font-display: swap; }`; document.head.appendChild(style); @@ -2990,11 +3013,25 @@ export default function VanillaQuote() { ``` ```js src/font.js hidden +<<<<<<< HEAD // Aggiungi un parametro univoco così il font non è in cache // e ogni esecuzione mostra la fase di caricamento. export function freshFontUrl() { +======= +export function freshStylesheetUrl() { + // Add a unique parameter so the stylesheet isn't cached. +>>>>>>> 046f17d04295ba047bb5739026b4ac3110f17028 + return ( + 'https://fonts.googleapis.com/css2?family=Caveat&display=swap' + + '&t=' + + Date.now() + ); +} + +export function freshFontUrl() { + // Add a unique parameter so the font isn't cached. return ( - 'https://raw.githubusercontent.com/google/fonts/main/ofl/caveat/Caveat%5Bwght%5D.ttf' + + 'https://fonts.gstatic.com/s/caveat/v23/WnznHAc5bAfYB2QRah7pcpNvOx-pjfJ9eIWpYT5Kmgq3sw.woff2' + '?t=' + Date.now() ); @@ -3032,7 +3069,7 @@ export function fetchQuote() { margin-top: 1em; } .fancy { - font-family: 'Fancy', sans-serif; + font-family: 'Caveat', sans-serif; } .vanilla-fancy { font-family: 'VanillaFancy', sans-serif; @@ -3045,8 +3082,8 @@ hr { ```json package.json hidden { "dependencies": { - "react": "19.3.0-canary-f1f7ed2a-20260904", - "react-dom": "19.3.0-canary-f1f7ed2a-20260904", + "react": "19.3.0", + "react-dom": "19.3.0", "react-scripts": "latest" } } @@ -3058,23 +3095,34 @@ hr { ### Attendere il caricamento di un'immagine {/*waiting-for-an-image-to-load*/} +<<<<<<< HEAD Quando un [``](/reference/react/ViewTransition) anima la rivelazione di un boundary Suspense, React attende il caricamento delle immagini visibili, fino a un timeout, così l'animazione non inizia con un'immagine a metà caricamento. Questo avviene solo durante un aggiornamento con ``. Aggiungere un gestore `onLoad` esclude una specifica immagine da questo comportamento, anche dentro un ``. Nell'esempio sotto, il boundary Suspense è avvolto in un `` e mostra uno skeleton del profilo finché il ritratto non è caricato. A titolo di confronto, il secondo pulsante esegue lo stesso aggiornamento senza React. Nulla attende l'immagine, quindi la card appare immediatamente e l'immagine compare quando si carica: +======= +When a Suspense boundary reveals content inside a [``](/reference/react/ViewTransition), React waits up to 500 ms for visible images to load before starting the animation. Setting `loading="lazy"` or adding an `onLoad` handler opts an image out. + +Compare the same boundary inside and outside a ``. Inside, React keeps the profile skeleton visible for up to 500 ms while the image loads, so the card can be revealed with its image already in place. Outside, Suspense stops showing the skeleton as soon as the Promise resolves. If the image is still loading, the card appears first and the image pops in afterward: +>>>>>>> 046f17d04295ba047bb5739026b4ac3110f17028 ```js -import { ViewTransition, Suspense, useState, startTransition } from 'react'; -import { freshImageUrl } from './image.js'; -import VanillaProfile from './VanillaProfile.js'; +import { + ViewTransition, + Suspense, + use, + useState, +} from 'react'; +import { fetchImageSrc } from './image.js'; -function Profile({ src }) { +function Profile({ cacheKey }) { + const src = use(fetchImageSrc(cacheKey)); return (
- Jack Pope +

Jack Pope

); @@ -3090,56 +3138,57 @@ function ProfilePlaceholder() { } export default function App() { - const [src, setSrc] = useState(null); + const [showWithTransition, setShowWithTransition] = + useState(false); + const [showWithoutTransition, setShowWithoutTransition] = + useState(false); return ( <> - - {src && ( + {showWithTransition && ( }> - + )}
- - - ); -} -``` - -```js src/VanillaProfile.js -import { useRef } from 'react'; -import { freshImageUrl } from './image.js'; - -export default function VanillaProfile() { - const ref = useRef(null); - function show() { - ref.current.innerHTML = `
- Jack Pope -

Jack Pope

-
`; - } - return ( - <> - -
+ + {showWithoutTransition && ( + }> + + + )} ); } ``` ```js src/image.js hidden +<<<<<<< HEAD // Aggiungi un parametro univoco così l'immagine non è in cache // e ogni esecuzione mostra la fase di caricamento. export function freshImageUrl() { +======= +// Normally, the caching logic would be inside a framework. +const cache = new Map(); + +export function fetchImageSrc(cacheKey) { + if (!cache.has(cacheKey)) { + cache.set(cacheKey, loadImageSrc()); + } + return cache.get(cacheKey); +} + +async function loadImageSrc() { + // Delay the response so the Suspense fallback is visible. + await new Promise(resolve => setTimeout(resolve, 1000)); + // Add a unique parameter so the image isn't cached. +>>>>>>> 046f17d04295ba047bb5739026b4ac3110f17028 return 'https://react.dev/images/team/jack-pope.jpg?t=' + Date.now(); } ``` @@ -3178,8 +3227,8 @@ hr { ```json package.json hidden { "dependencies": { - "react": "19.3.0-canary-f1f7ed2a-20260904", - "react-dom": "19.3.0-canary-f1f7ed2a-20260904", + "react": "19.3.0", + "react-dom": "19.3.0", "react-scripts": "latest" } } @@ -3209,7 +3258,7 @@ function ProfileCard({ resources }) { <>
- Jack Pope +

Jack Pope

{quote}

@@ -3269,7 +3318,6 @@ import { freshStylesheetUrl, freshImageUrl } from './resources.js'; export default function VanillaProfileCard() { const ref = useRef(null); async function show() { - const quote = await fetchQuote(); const doc = ref.current.contentWindow.document; doc.open(); doc.write(` @@ -3279,17 +3327,34 @@ export default function VanillaProfileCard() { .profile-card img { border-radius: 50%; background: #dfe3e9; } .name { margin: 0 0 4px; font-family: 'Caveat', sans-serif; font-size: 22px; line-height: 28px; font-weight: bold; } .bio { margin: 0; font-family: 'Caveat', sans-serif; font-size: 20px; line-height: 26px; } + .avatar-placeholder { width: 80px; height: 80px; border-radius: 50%; background: #dfe3e9; } + .name-placeholder, .bio-placeholder { border-radius: 4px; background: #dfe3e9; color: transparent; } + .name-placeholder { width: 90px; } + .bio-placeholder { width: 220px; height: 52px; }
- Jack Pope +
-

Jack Pope

-

${quote}

+

 

+

 

- `); doc.close(); + + const quote = await fetchQuote(); + doc.body.innerHTML = ` +
+ +
+

Jack Pope

+

${quote}

+
+
`; + const stylesheet = doc.createElement('link'); + stylesheet.rel = 'stylesheet'; + stylesheet.href = freshStylesheetUrl(); + doc.head.appendChild(stylesheet); } return ( <> @@ -3382,6 +3447,7 @@ hr { } .bio-placeholder { width: 220px; + height: 52px; } .vanilla-frame { display: block; @@ -3395,8 +3461,8 @@ hr { ```json package.json hidden { "dependencies": { - "react": "19.3.0-canary-f1f7ed2a-20260904", - "react-dom": "19.3.0-canary-f1f7ed2a-20260904", + "react": "19.3.0", + "react-dom": "19.3.0", "react-scripts": "latest" } } diff --git a/src/content/reference/react/ViewTransition.md b/src/content/reference/react/ViewTransition.md index 1011a1c96..17595bb76 100644 --- a/src/content/reference/react/ViewTransition.md +++ b/src/content/reference/react/ViewTransition.md @@ -1253,9 +1253,9 @@ It's important to properly use keys to preserve identity when reordering lists. ### Animating from Suspense content {/*animating-from-suspense-content*/} -Like any Transition, React waits for data and new CSS (``) before running the animation. In addition to this, ViewTransitions also wait up to 500ms for new fonts to load before starting the animation to avoid them flickering in later. For the same reason, an image wrapped in ViewTransition will wait for the image to load. See examples of [waiting for a font](/reference/react/Suspense#waiting-for-a-font-to-load) and [waiting for an image](/reference/react/Suspense#waiting-for-an-image-to-load) on the Suspense page. +Like any Transition, React waits for data and new CSS (``) before running the animation. `` also waits up to 500 ms for new fonts and visible images to load so they don't flicker in after the animation starts. See examples of [waiting for a font](/reference/react/Suspense#waiting-for-a-font-to-load) and [waiting for an image](/reference/react/Suspense#waiting-for-an-image-to-load) on the Suspense page. -If it's inside a new Suspense boundary instance, then the fallback is shown first. After the Suspense boundary fully loads, it triggers the `` to animate the reveal to the content. +If the content is inside a new Suspense boundary, React first shows the fallback. After the boundary finishes loading, `` animates the reveal to the content. There are two ways to animate Suspense boundaries depending on where you place the ``: @@ -1315,7 +1315,7 @@ export function VideoPlaceholder() { ``` ```js -import {ViewTransition, useState, startTransition, Suspense} from 'react'; +import { ViewTransition, Suspense, useState } from 'react'; import {Video, VideoPlaceholder} from './Video'; import {useLazyVideoData} from './data'; @@ -1328,12 +1328,7 @@ export default function Component() { const [showItem, setShowItem] = useState(false); return ( <> - {showItem ? ( @@ -1486,8 +1481,8 @@ button:hover { ```json package.json hidden { "dependencies": { - "react": "19.3.0-canary-f1f7ed2a-20260904", - "react-dom": "19.3.0-canary-f1f7ed2a-20260904", + "react": "19.3.0", + "react-dom": "19.3.0", "react-scripts": "latest" } }