From 2b508a296e5dc9d7085e8303ad9c039d7ead6c7f Mon Sep 17 00:00:00 2001 From: Heorhii Shvab Date: Thu, 17 Oct 2024 13:59:21 +0300 Subject: [PATCH] Finished translation of Suspense page --- TRANSLATION.md | 2 +- src/content/reference/react/Suspense.md | 456 ++++++++++++------------ 2 files changed, 229 insertions(+), 229 deletions(-) diff --git a/TRANSLATION.md b/TRANSLATION.md index 18283fba3..43e33d2c6 100644 --- a/TRANSLATION.md +++ b/TRANSLATION.md @@ -122,7 +122,7 @@ | error boundary | запобіжник | | error log | лог помилок | | event handler | обробник події | -| fallback | запасний | +| fallback | запасний варіант | | feature | особливість | | framework | фреймворк | | function component | функційний компонент | diff --git a/src/content/reference/react/Suspense.md b/src/content/reference/react/Suspense.md index 7622aa182..1d84b6eb1 100644 --- a/src/content/reference/react/Suspense.md +++ b/src/content/reference/react/Suspense.md @@ -4,7 +4,7 @@ title: -`` lets you display a fallback until its children have finished loading. +`` дає вам змогу відображати запасний варіант (fallback), доки його дочірні компоненти не завершать завантаження. ```js @@ -19,28 +19,28 @@ title: --- -## Reference {/*reference*/} +## Опис {/*reference*/} ### `` {/*suspense*/} -#### Props {/*props*/} -* `children`: The actual UI you intend to render. If `children` suspends while rendering, the Suspense boundary will switch to rendering `fallback`. -* `fallback`: An alternate UI to render in place of the actual UI if it has not finished loading. Any valid React node is accepted, though in practice, a fallback is a lightweight placeholder view, such as a loading spinner or skeleton. Suspense will automatically switch to `fallback` when `children` suspends, and back to `children` when the data is ready. If `fallback` suspends while rendering, it will activate the closest parent Suspense boundary. +#### Пропси {/*props*/} +* `children`: Очікуваний UI, який ви хочете відрендерити. Якщо `children` затримується (suspends) під час рендерингу, межа (boundary) Suspense перемкнеться на рендер `fallback`. +* `fallback`: Альтернативний UI, який рендериться замість очікуваного UI, якщо той ще не завершив завантаження. Проп приймає будь-який валідний React-вузол, хоча на практиці запасний варіант є невеличким елементом для заповнення області перегляду, як-от спінер чи скелетон. Suspense автоматично перемкнеться на `fallback`, коли `children` затримується, і назад на `children`, коли дані будуть готові. Якщо `fallback` затримується під час рендеру, найближча батьківська межа Suspense буде активована. -#### Caveats {/*caveats*/} +#### Застереження {/*caveats*/} -- React does not preserve any state for renders that got suspended before they were able to mount for the first time. When the component has loaded, React will retry rendering the suspended tree from scratch. -- If Suspense was displaying content for the tree, but then it suspended again, the `fallback` will be shown again unless the update causing it was caused by [`startTransition`](/reference/react/startTransition) or [`useDeferredValue`](/reference/react/useDeferredValue). -- If React needs to hide the already visible content because it suspended again, it will clean up [layout Effects](/reference/react/useLayoutEffect) in the content tree. When the content is ready to be shown again, React will fire the layout Effects again. This ensures that Effects measuring the DOM layout don't try to do this while the content is hidden. -- React includes under-the-hood optimizations like *Streaming Server Rendering* and *Selective Hydration* that are integrated with Suspense. Read [an architectural overview](https://github.com/reactwg/react-18/discussions/37) and watch [a technical talk](https://www.youtube.com/watch?v=pj5N-Khihgc) to learn more. +- React не зберігає жодного стану для рендерів, затриманих до першого монтування (mount). Коли компонент завантажиться, React ще раз спробує відрендерити затримане дерево компонентів із нуля. +- Якщо Suspense відображав вміст, але затримався повторно, `fallback` буде відображено знову, за винятком випадків, коли оновлення, яке це спричинило, зумовлене функціями [`startTransition`](/reference/react/startTransition) або [`useDeferredValue`](/reference/react/useDeferredValue). +- Якщо React потрібно сховати вже видимий вміст через повторну затримку, він скине [ефекти макета](/reference/react/useLayoutEffect) в дереві компонентів. Коли вміст буде знову готовий до показу, React викличе ефекти макета знову. Це запевняє, що ефекти, які проводять виміри DOM-макета, не намагатимуться робити цього, доки вміст прихований. +- React має вбудовані оптимізації інтегровані в Suspense, як-от *Потоковий рендеринг на стороні сервера* і *Вибіркову гідрацію*. Прочитайте [архітектурний огляд](https://github.com/reactwg/react-18/discussions/37) і подивіться [технічну доповідь](https://www.youtube.com/watch?v=pj5N-Khihgc), щоб дізнатися більше. --- -## Usage {/*usage*/} +## Використання {/*usage*/} -### Displaying a fallback while content is loading {/*displaying-a-fallback-while-content-is-loading*/} +### Відображення запасного варіанту під час завантаження вмісту {/*displaying-a-fallback-while-content-is-loading*/} -You can wrap any part of your application with a Suspense boundary: +Ви можете загорнути будь-яку частину вашого застосунку в межу Suspense: ```js [[1, 1, ""], [2, 2, ""]] }> @@ -48,9 +48,9 @@ You can wrap any part of your application with a Suspense boundary: ``` -React will display your loading fallback until all the code and data needed by the children has been loaded. +React відображатиме ваш запасний варіант завантаження, доки всесь код та дані, які потребує дочірній компонент, не будуть завантажені. -In the example below, the `Albums` component *suspends* while fetching the list of albums. Until it's ready to render, React switches the closest Suspense boundary above to show the fallback--your `Loading` component. Then, when the data loads, React hides the `Loading` fallback and renders the `Albums` component with data. +У прикладі вище, компонент `Albums` *затримується* під час отримання списку альбомів. Доки він не буде готовим до рендеру, React переключиться на найближчу межу Suspense вверху дерева, щоб показати запасний варіант - ваш компонент `Loading`. Коли дані завантажаться, React сховає запасний варіант `Loading` і відрендерить компонент `Albums` з даними. @@ -87,7 +87,7 @@ export default function App() { } else { return ( ); } @@ -110,18 +110,18 @@ export default function ArtistPage({ artist }) { } function Loading() { - return

🌀 Loading...

; + return

🌀 Завантаження...

; } ``` ```js src/Albums.js hidden import { fetchData } from './data.js'; -// Note: this component is written using an experimental API -// that's not yet available in stable versions of React. +// Примітка: цей компонент створено з використанням експериментального API, +// яке ще не доступне в стабільних версіях React. -// For a realistic example you can follow today, try a framework -// that's integrated with Suspense, like Relay or Next.js. +// Для реалістичного прикладу, який ви можете спробувати сьогодні, скористайтеся фреймворком +// з інтегрованим Suspense, як-от Relay чи Next.js. export default function Albums({ artistId }) { const albums = use(fetchData(`/${artistId}/albums`)); @@ -136,8 +136,8 @@ export default function Albums({ artistId }) { ); } -// This is a workaround for a bug to get the demo running. -// TODO: replace with real implementation when the bug is fixed. +// Це тимчасове рішення для виправлення помилки, додане, щоб демонстрація працювала. +// TODO: замінити реальною реалізацією, коли помилку буде виправлено. function use(promise) { if (promise.status === 'fulfilled') { return promise.value; @@ -163,9 +163,9 @@ function use(promise) { ``` ```js src/data.js hidden -// Note: the way you would do data fetching depends on -// the framework that you use together with Suspense. -// Normally, the caching logic would be inside a framework. +// Примітка: те, як ви будете отримувати дані, залежить +// від фреймворку, який ви використовуєте разом із Suspense. +// Зазвичай логіка кешування буде всередині фреймворку. let cache = new Map(); @@ -185,7 +185,7 @@ async function getData(url) { } async function getAlbums() { - // Add a fake delay to make waiting noticeable. + // Додаємо штучну затримку, щоб очікування було помітним. await new Promise(resolve => { setTimeout(resolve, 3000); }); @@ -250,25 +250,25 @@ async function getAlbums() { -**Only Suspense-enabled data sources will activate the Suspense component.** They include: +**Тільки джерела даних із підтримкою Suspense активують компонент Suspense.** Вони включають: -- Data fetching with Suspense-enabled frameworks like [Relay](https://relay.dev/docs/guided-tour/rendering/loading-states/) and [Next.js](https://nextjs.org/docs/getting-started/react-essentials) -- Lazy-loading component code with [`lazy`](/reference/react/lazy) -- Reading the value of a Promise with [`use`](/reference/react/use) +- Отримання даних із фреймворками, що підтримують Suspense, наприклад, [Relay](https://relay.dev/docs/guided-tour/rendering/loading-states/) та [Next.js](https://nextjs.org/docs/getting-started/react-essentials) +- Компоненти з відкладеним завантаженням, які використовують [`lazy`](/reference/react/lazy) +- Зчитування значення Promise з [`use`](/reference/react/use) -Suspense **does not** detect when data is fetched inside an Effect or event handler. +Suspense **не** реагує, коли дані отримуються всередині ефекта чи обробника подій. -The exact way you would load data in the `Albums` component above depends on your framework. If you use a Suspense-enabled framework, you'll find the details in its data fetching documentation. +Спосіб, у який ви будете отримувати дані в компоненті `Albums`, наведеному вище, залежить від вашого фреймоворку. Якщо ви використовуєте фреймворк із підтримкою Suspense, ви знайдете деталі в його документації щодо отримання даних. -Suspense-enabled data fetching without the use of an opinionated framework is not yet supported. The requirements for implementing a Suspense-enabled data source are unstable and undocumented. An official API for integrating data sources with Suspense will be released in a future version of React. +Отримання даних із Suspense, але без використання фреймворку, наразі не підтримується. Вимоги до реалізації джерела даних із підтримкою Suspense нестабільні й незадокументовані. Офіційний API для інтеграції джерел даних та Suspense буде випущено в майбутній версії React. --- -### Revealing content together at once {/*revealing-content-together-at-once*/} +### Одночасне відображення всього вмісту {/*revealing-content-together-at-once*/} -By default, the whole tree inside Suspense is treated as a single unit. For example, even if *only one* of these components suspends waiting for some data, *all* of them together will be replaced by the loading indicator: +Початково, усе дерево всередині Suspense сприймається як один компонент. Для прикладу, навіть якщо *тільки один* із цих компонентів затримується, очікуючи на дані, *всі* з них буде замінено на індикатор завантаження: ```js {2-5} }> @@ -279,9 +279,9 @@ By default, the whole tree inside Suspense is treated as a single unit. For exam ``` -Then, after all of them are ready to be displayed, they will all appear together at once. +Коли всі з них будуть готові до відображення, вони зв'являться всі разом в один момент. -In the example below, both `Biography` and `Albums` fetch some data. However, because they are grouped under a single Suspense boundary, these components always "pop in" together at the same time. +У прикладі нижче, обидва компоненти `Biography` і `Albums` отримують якісь дані. Проте, через те що вони згруповані всередині одної межі Suspense, ці компоненти завжди "вискакуватимуть" одночасно. @@ -318,7 +318,7 @@ export default function App() { } else { return ( ); } @@ -346,7 +346,7 @@ export default function ArtistPage({ artist }) { } function Loading() { - return

🌀 Loading...

; + return

🌀 Завантаження...

; } ``` @@ -363,11 +363,11 @@ export default function Panel({ children }) { ```js src/Biography.js hidden import { fetchData } from './data.js'; -// Note: this component is written using an experimental API -// that's not yet available in stable versions of React. +// Примітка: цей компонент створено з використанням експериментального API, +// яке ще не доступне в стабільних версіях React. -// For a realistic example you can follow today, try a framework -// that's integrated with Suspense, like Relay or Next.js. +// Для реалістичного прикладу, який ви можете спробувати сьогодні, скористайтеся фреймворком +// з інтегрованим Suspense, як-от Relay чи Next.js. export default function Biography({ artistId }) { const bio = use(fetchData(`/${artistId}/bio`)); @@ -378,8 +378,8 @@ export default function Biography({ artistId }) { ); } -// This is a workaround for a bug to get the demo running. -// TODO: replace with real implementation when the bug is fixed. +// Це тимчасове рішення для виправлення помилки, додане, щоб демонстрація працювала. +// TODO: замінити реальною реалізацією, коли помилку буде виправлено. function use(promise) { if (promise.status === 'fulfilled') { return promise.value; @@ -407,11 +407,11 @@ function use(promise) { ```js src/Albums.js hidden import { fetchData } from './data.js'; -// Note: this component is written using an experimental API -// that's not yet available in stable versions of React. +// Примітка: цей компонент створено з використанням експериментального API, +// яке ще не доступне в стабільних версіях React. -// For a realistic example you can follow today, try a framework -// that's integrated with Suspense, like Relay or Next.js. +// Для реалістичного прикладу, який ви можете спробувати сьогодні, скористайтеся фреймворком +// з інтегрованим Suspense, як-от Relay чи Next.js. export default function Albums({ artistId }) { const albums = use(fetchData(`/${artistId}/albums`)); @@ -426,8 +426,8 @@ export default function Albums({ artistId }) { ); } -// This is a workaround for a bug to get the demo running. -// TODO: replace with real implementation when the bug is fixed. +// Це тимчасове рішення для виправлення помилки, додане, щоб демонстрація працювала. +// TODO: замінити реальною реалізацією, коли помилку буде виправлено. function use(promise) { if (promise.status === 'fulfilled') { return promise.value; @@ -453,9 +453,9 @@ function use(promise) { ``` ```js src/data.js hidden -// Note: the way you would do data fetching depends on -// the framework that you use together with Suspense. -// Normally, the caching logic would be inside a framework. +// Примітка: те, як ви будете отримувати дані, залежить +// від фреймворку, який ви використовуєте разом із Suspense. +// Зазвичай логіка кешування буде всередині фреймворку. let cache = new Map(); @@ -477,19 +477,19 @@ async function getData(url) { } async function getBio() { - // Add a fake delay to make waiting noticeable. + // Додаємо штучну затримку, щоб очікування було помітним. await new Promise(resolve => { setTimeout(resolve, 1500); }); - return `The Beatles were an English rock band, - formed in Liverpool in 1960, that comprised - John Lennon, Paul McCartney, George Harrison - and Ringo Starr.`; + return `The Beatles був англійським рок-гуртом, + cтвореним у Ліверпулі в 1960 році, до складу якого + входили Джон Леннон (John Lennon), Пол Маккартні (Paul McCartney), + Джордж Гаррісон (George Harrison) і Рінго Старр (Ringo Starr).`; } async function getAlbums() { - // Add a fake delay to make waiting noticeable. + // Додаємо штучну затримку, щоб очікування було помітним. await new Promise(resolve => { setTimeout(resolve, 3000); }); @@ -563,7 +563,7 @@ async function getAlbums() {
-Components that load data don't have to be direct children of the Suspense boundary. For example, you can move `Biography` and `Albums` into a new `Details` component. This doesn't change the behavior. `Biography` and `Albums` share the same closest parent Suspense boundary, so their reveal is coordinated together. +Компоненти, що завантажують дані, можуть не бути прямими дочірніми компонентами межі Suspense. Наприклад, ви можете перенести `Biography` і `Albums` у новий компонент `Details`. Це не вплине на поведінку. `Biography` і `Albums` поділяють одну найближчу батьківську межу Suspense, тому їхнє відображення координується разом. ```js {2,8-11} }> @@ -584,9 +584,9 @@ function Details({ artistId }) { --- -### Revealing nested content as it loads {/*revealing-nested-content-as-it-loads*/} +### Відображення вкладеного вмісту поступово, відповідно до його завантаження {/*revealing-nested-content-as-it-loads*/} -When a component suspends, the closest parent Suspense component shows the fallback. This lets you nest multiple Suspense components to create a loading sequence. Each Suspense boundary's fallback will be filled in as the next level of content becomes available. For example, you can give the album list its own fallback: +Коли компонент затримується, найближчий батьківський компонент Suspense відображає запасний варіант. Це дає вам змогу вкладувати кілька компонентів Suspense, щоб сворити послідовність завантаження. Кожен запасний варіант Suspense буде замінено, коли наступний рівень вмісту буде доступним. Наприклад, ви можете дати списку альбомів власний запасний варіант: ```js {3,7} }> @@ -599,14 +599,14 @@ When a component suspends, the closest parent Suspense component shows the fallb ``` -With this change, displaying the `Biography` doesn't need to "wait" for the `Albums` to load. +Із цією зміною, для відображення `Biography` не потрібно "чекати" завантаження `Albums`. -The sequence will be: +Послідовність буде такою: -1. If `Biography` hasn't loaded yet, `BigSpinner` is shown in place of the entire content area. -1. Once `Biography` finishes loading, `BigSpinner` is replaced by the content. -1. If `Albums` hasn't loaded yet, `AlbumsGlimmer` is shown in place of `Albums` and its parent `Panel`. -1. Finally, once `Albums` finishes loading, it replaces `AlbumsGlimmer`. +1. Якщо `Biography` ще не завантажився, `BigSpinner` буде показано замість усього вмісту. +1. Як тільки `Biography` закінчить завантаження, `BigSpinner` буде замінено бажаним вмістом. +1. Якщо `Albums` ще не завантажився, `AlbumsGlimmer` буде показано замість `Albums` і його батьківського компонента `Panel`. +1. Нарешті, як тільки `Albums` закінчить завантаження, він замінить `AlbumsGlimmer`. @@ -643,7 +643,7 @@ export default function App() { } else { return ( ); } @@ -673,7 +673,7 @@ export default function ArtistPage({ artist }) { } function BigSpinner() { - return

🌀 Loading...

; + return

🌀 Завантаження...

; } function AlbumsGlimmer() { @@ -700,11 +700,11 @@ export default function Panel({ children }) { ```js src/Biography.js hidden import { fetchData } from './data.js'; -// Note: this component is written using an experimental API -// that's not yet available in stable versions of React. +// Примітка: цей компонент створено з використанням експериментального API, +// яке ще не доступне в стабільних версіях React. -// For a realistic example you can follow today, try a framework -// that's integrated with Suspense, like Relay or Next.js. +// Для реалістичного прикладу, який ви можете спробувати сьогодні, скористайтеся фреймворком +// з інтегрованим Suspense, як-от Relay чи Next.js. export default function Biography({ artistId }) { const bio = use(fetchData(`/${artistId}/bio`)); @@ -715,8 +715,8 @@ export default function Biography({ artistId }) { ); } -// This is a workaround for a bug to get the demo running. -// TODO: replace with real implementation when the bug is fixed. +// Це тимчасове рішення для виправлення помилки, додане, щоб демонстрація працювала. +// TODO: замінити реальною реалізацією, коли помилку буде виправлено. function use(promise) { if (promise.status === 'fulfilled') { return promise.value; @@ -744,11 +744,11 @@ function use(promise) { ```js src/Albums.js hidden import { fetchData } from './data.js'; -// Note: this component is written using an experimental API -// that's not yet available in stable versions of React. +// Примітка: цей компонент створено з використанням експериментального API, +// яке ще не доступне в стабільних версіях React. -// For a realistic example you can follow today, try a framework -// that's integrated with Suspense, like Relay or Next.js. +// Для реалістичного прикладу, який ви можете спробувати сьогодні, скористайтеся фреймворком +// з інтегрованим Suspense, як-от Relay чи Next.js. export default function Albums({ artistId }) { const albums = use(fetchData(`/${artistId}/albums`)); @@ -763,8 +763,8 @@ export default function Albums({ artistId }) { ); } -// This is a workaround for a bug to get the demo running. -// TODO: replace with real implementation when the bug is fixed. +// Це тимчасове рішення для виправлення помилки, додане, щоб демонстрація працювала. +// TODO: замінити реальною реалізацією, коли помилку буде виправлено. function use(promise) { if (promise.status === 'fulfilled') { return promise.value; @@ -790,9 +790,9 @@ function use(promise) { ``` ```js src/data.js hidden -// Note: the way you would do data fetching depends on -// the framework that you use together with Suspense. -// Normally, the caching logic would be inside a framework. +// Примітка: те, як ви будете отримувати дані, залежить +// від фреймворку, який ви використовуєте разом із Suspense. +// Зазвичай логіка кешування буде всередині фреймворку. let cache = new Map(); @@ -814,19 +814,19 @@ async function getData(url) { } async function getBio() { - // Add a fake delay to make waiting noticeable. + // Додаємо штучну затримку, щоб очікування було помітним. await new Promise(resolve => { setTimeout(resolve, 500); }); - return `The Beatles were an English rock band, - formed in Liverpool in 1960, that comprised - John Lennon, Paul McCartney, George Harrison - and Ringo Starr.`; + return `The Beatles був англійським рок-гуртом, + cтвореним у Ліверпулі в 1960 році, до складу якого + входили Джон Леннон (John Lennon), Пол Маккартні (Paul McCartney), + Джордж Гаррісон (George Harrison) і Рінго Старр (Ringo Starr).`; } async function getAlbums() { - // Add a fake delay to make waiting noticeable. + // Додаємо штучну затримку, щоб очікування було помітним. await new Promise(resolve => { setTimeout(resolve, 3000); }); @@ -917,15 +917,15 @@ async function getAlbums() {
-Suspense boundaries let you coordinate which parts of your UI should always "pop in" together at the same time, and which parts should progressively reveal more content in a sequence of loading states. You can add, move, or delete Suspense boundaries in any place in the tree without affecting the rest of your app's behavior. +Межі Suspense дають вам змогу контролювати, які частини UI повинні завжди з'являтися одночасно, і які частини повинні поступово показувати більше вмісту відповідно до послідовності завантаження. Ви можете додавати, переставляти або видаляти межі Suspense в будь-якому місці дерева компонетів, без впливу на поведінку решти застосунку. -Don't put a Suspense boundary around every component. Suspense boundaries should not be more granular than the loading sequence that you want the user to experience. If you work with a designer, ask them where the loading states should be placed--it's likely that they've already included them in their design wireframes. +Не ставте межу Suspense навколо кожного компонента. Межі Suspense не повинні бути більш частими, ніж послідовність завантаження, яку ви хочете, щоб користувач побачив. Якщо ви працюєте з дизайнером, запитайте його, де повинні відображатися індикатори завантаження — висока вірогідність, що вони вже включили їх у макети дизайну. --- -### Showing stale content while fresh content is loading {/*showing-stale-content-while-fresh-content-is-loading*/} +### Відображення застарілого вмісту під час завантаження нового {/*showing-stale-content-while-fresh-content-is-loading*/} -In this example, the `SearchResults` component suspends while fetching the search results. Type `"a"`, wait for the results, and then edit it to `"ab"`. The results for `"a"` will get replaced by the loading fallback. +У цьому прикладі, компонент `SearchResults` затримується, доки завантажує результати пошуку. Введіть `"a"`, зачекайте на результат, а тоді змініть на `"ab"`. Результати для `"a"` будуть замінені запасним варінтом завантаження. @@ -953,10 +953,10 @@ export default function App() { return ( <> - Loading...}> + Завантаження...}> @@ -967,11 +967,11 @@ export default function App() { ```js src/SearchResults.js hidden import { fetchData } from './data.js'; -// Note: this component is written using an experimental API -// that's not yet available in stable versions of React. +// Примітка: цей компонент створено з використанням експериментального API, +// яке ще не доступне в стабільних версіях React. -// For a realistic example you can follow today, try a framework -// that's integrated with Suspense, like Relay or Next.js. +// Для реалістичного прикладу, який ви можете спробувати сьогодні, скористайтеся фреймворком +// з інтегрованим Suspense, як-от Relay чи Next.js. export default function SearchResults({ query }) { if (query === '') { @@ -979,7 +979,7 @@ export default function SearchResults({ query }) { } const albums = use(fetchData(`/search?q=${query}`)); if (albums.length === 0) { - return

No matches for "{query}"

; + return

Не знайдено результатів для "{query}"

; } return (
    @@ -992,8 +992,8 @@ export default function SearchResults({ query }) { ); } -// This is a workaround for a bug to get the demo running. -// TODO: replace with real implementation when the bug is fixed. +// Це тимчасове рішення для виправлення помилки, додане, щоб демонстрація працювала. +// TODO: замінити реальною реалізацією, коли помилку буде виправлено. function use(promise) { if (promise.status === 'fulfilled') { return promise.value; @@ -1019,9 +1019,9 @@ function use(promise) { ``` ```js src/data.js hidden -// Note: the way you would do data fetching depends on -// the framework that you use together with Suspense. -// Normally, the caching logic would be inside a framework. +// Примітка: те, як ви будете отримувати дані, залежить +// від фреймворку, який ви використовуєте разом із Suspense. +// Зазвичай логіка кешування буде всередині фреймворку. let cache = new Map(); @@ -1041,7 +1041,7 @@ async function getData(url) { } async function getSearchResults(query) { - // Add a fake delay to make waiting noticeable. + // Додаємо штучну затримку, щоб очікування було помітним. await new Promise(resolve => { setTimeout(resolve, 500); }); @@ -1117,7 +1117,7 @@ input { margin: 10px; } -A common alternative UI pattern is to *defer* updating the list and to keep showing the previous results until the new results are ready. The [`useDeferredValue`](/reference/react/useDeferredValue) Hook lets you pass a deferred version of the query down: +Поширеним альтернативним UI паттерном є *відкладене* оновлення списку з показом попередніх результатів, доки нові результати не будуть готові. Хук [`useDeferredValue`](/reference/react/useDeferredValue) дає змогу передавати відкладений варіант запиту вниз по дереву: ```js {3,11} export default function App() { @@ -1126,10 +1126,10 @@ export default function App() { return ( <> - Loading...}> + Завантаження...}> @@ -1137,9 +1137,9 @@ export default function App() { } ``` -The `query` will update immediately, so the input will display the new value. However, the `deferredQuery` will keep its previous value until the data has loaded, so `SearchResults` will show the stale results for a bit. +`query` оновиться одразу, тому пошуковий рядок відображатиме нове значення. Проте, `deferredQuery` збереже попереднє значення, доки дані не будуть завантажені, тож `SearchResults` на деякий час відобразить застарілі результати. -To make it more obvious to the user, you can add a visual indication when the stale result list is displayed: +Щоб зробити це більш очевидним для користувача, ви можете додати візуальний індикатор під час відображення застарілого вмісту: ```js {2}
    ``` -Enter `"a"` in the example below, wait for the results to load, and then edit the input to `"ab"`. Notice how instead of the Suspense fallback, you now see the dimmed stale result list until the new results have loaded: +Введіть `"a"` у прикладі нижче, зачекайте на результат, тоді змініть значення на `"ab"`. Зверніть увагу, як замість запасного варіанту, ви бачите затемнений список попередніх результатів, доки нові результати не завантажилися: @@ -1180,10 +1180,10 @@ export default function App() { return ( <> - Loading...}> + Завантаження...}>
    @@ -1196,11 +1196,11 @@ export default function App() { ```js src/SearchResults.js hidden import { fetchData } from './data.js'; -// Note: this component is written using an experimental API -// that's not yet available in stable versions of React. +// Примітка: цей компонент створено з використанням експериментального API, +// яке ще не доступне в стабільних версіях React. -// For a realistic example you can follow today, try a framework -// that's integrated with Suspense, like Relay or Next.js. +// Для реалістичного прикладу, який ви можете спробувати сьогодні, скористайтеся фреймворком +// з інтегрованим Suspense, як-от Relay чи Next.js. export default function SearchResults({ query }) { if (query === '') { @@ -1208,7 +1208,7 @@ export default function SearchResults({ query }) { } const albums = use(fetchData(`/search?q=${query}`)); if (albums.length === 0) { - return

    No matches for "{query}"

    ; + return

    Не знайдено результатів для "{query}"

    ; } return (
      @@ -1221,8 +1221,8 @@ export default function SearchResults({ query }) { ); } -// This is a workaround for a bug to get the demo running. -// TODO: replace with real implementation when the bug is fixed. +// Це тимчасове рішення для виправлення помилки, додане, щоб демонстрація працювала. +// TODO: замінити реальною реалізацією, коли помилку буде виправлено. function use(promise) { if (promise.status === 'fulfilled') { return promise.value; @@ -1248,9 +1248,9 @@ function use(promise) { ``` ```js src/data.js hidden -// Note: the way you would do data fetching depends on -// the framework that you use together with Suspense. -// Normally, the caching logic would be inside a framework. +// Примітка: те, як ви будете отримувати дані, залежить +// від фреймворку, який ви використовуєте разом із Suspense. +// Зазвичай логіка кешування буде всередині фреймворку. let cache = new Map(); @@ -1270,7 +1270,7 @@ async function getData(url) { } async function getSearchResults(query) { - // Add a fake delay to make waiting noticeable. + // Додаємо штучну затримку, щоб очікування було помітним. await new Promise(resolve => { setTimeout(resolve, 500); }); @@ -1348,15 +1348,15 @@ input { margin: 10px; } -Both deferred values and [Transitions](#preventing-already-revealed-content-from-hiding) let you avoid showing Suspense fallback in favor of inline indicators. Transitions mark the whole update as non-urgent so they are typically used by frameworks and router libraries for navigation. Deferred values, on the other hand, are mostly useful in application code where you want to mark a part of UI as non-urgent and let it "lag behind" the rest of the UI. +Як затримані значення так і [переходи](#preventing-already-revealed-content-from-hiding) дають вам змогу уникнути відображення запасного варіанту Suspense, натомість відображаючи індикатор безпосередньо у вмісті. Переходи відмічають оновлення як нетермінові, тож вони часто використовуються фреймворками та бібліотеками-маршрутизаторами для навігації. З іншого боку, відкладені значення, переважно використовуються в коді застосунку там, де ви хочете відмітити частину UI як нетермінову й дозволити їй "відставати" від решти UI. --- -### Preventing already revealed content from hiding {/*preventing-already-revealed-content-from-hiding*/} +### Запобігання заміни запасним варіантом уже відображеного вмісту {/*preventing-already-revealed-content-from-hiding*/} -When a component suspends, the closest parent Suspense boundary switches to showing the fallback. This can lead to a jarring user experience if it was already displaying some content. Try pressing this button: +Коли компонент затримується, найближча батьківська межа Suspense перемикається на показ запасного варіанту. Це може призвести до неприємного користувацького досвіду у випадку, якщо якийсь вміст уже відображався. Спробуйте настинути цю кнопку: @@ -1419,7 +1419,7 @@ function Router() { } function BigSpinner() { - return

      🌀 Loading...

      ; + return

      🌀 Завантаження...

      ; } ``` @@ -1428,7 +1428,7 @@ export default function Layout({ children }) { return (
      - Music Browser + Музичний браузер
      {children} @@ -1442,7 +1442,7 @@ export default function Layout({ children }) { export default function IndexPage({ navigate }) { return ( ); } @@ -1482,11 +1482,11 @@ function AlbumsGlimmer() { ```js src/Albums.js hidden import { fetchData } from './data.js'; -// Note: this component is written using an experimental API -// that's not yet available in stable versions of React. +// Примітка: цей компонент створено з використанням експериментального API, +// яке ще не доступне в стабільних версіях React. -// For a realistic example you can follow today, try a framework -// that's integrated with Suspense, like Relay or Next.js. +// Для реалістичного прикладу, який ви можете спробувати сьогодні, скористайтеся фреймворком +// з інтегрованим Suspense, як-от Relay чи Next.js. export default function Albums({ artistId }) { const albums = use(fetchData(`/${artistId}/albums`)); @@ -1501,8 +1501,8 @@ export default function Albums({ artistId }) { ); } -// This is a workaround for a bug to get the demo running. -// TODO: replace with real implementation when the bug is fixed. +// Це тимчасове рішення для виправлення помилки, додане, щоб демонстрація працювала. +// TODO: замінити реальною реалізацією, коли помилку буде виправлено. function use(promise) { if (promise.status === 'fulfilled') { return promise.value; @@ -1530,11 +1530,11 @@ function use(promise) { ```js src/Biography.js hidden import { fetchData } from './data.js'; -// Note: this component is written using an experimental API -// that's not yet available in stable versions of React. +// Примітка: цей компонент створено з використанням експериментального API, +// яке ще не доступне в стабільних версіях React. -// For a realistic example you can follow today, try a framework -// that's integrated with Suspense, like Relay or Next.js. +// Для реалістичного прикладу, який ви можете спробувати сьогодні, скористайтеся фреймворком +// з інтегрованим Suspense, як-от Relay чи Next.js. export default function Biography({ artistId }) { const bio = use(fetchData(`/${artistId}/bio`)); @@ -1545,8 +1545,8 @@ export default function Biography({ artistId }) { ); } -// This is a workaround for a bug to get the demo running. -// TODO: replace with real implementation when the bug is fixed. +// Це тимчасове рішення для виправлення помилки, додане, щоб демонстрація працювала. +// TODO: замінити реальною реалізацією, коли помилку буде виправлено. function use(promise) { if (promise.status === 'fulfilled') { return promise.value; @@ -1582,9 +1582,9 @@ export default function Panel({ children }) { ``` ```js src/data.js hidden -// Note: the way you would do data fetching depends on -// the framework that you use together with Suspense. -// Normally, the caching logic would be inside a framework. +// Примітка: те, як ви будете отримувати дані, залежить +// від фреймворку, який ви використовуєте разом із Suspense. +// Зазвичай логіка кешування буде всередині фреймворку. let cache = new Map(); @@ -1606,19 +1606,19 @@ async function getData(url) { } async function getBio() { - // Add a fake delay to make waiting noticeable. + // Додаємо штучну затримку, щоб очікування було помітним. await new Promise(resolve => { setTimeout(resolve, 500); }); - return `The Beatles were an English rock band, - formed in Liverpool in 1960, that comprised - John Lennon, Paul McCartney, George Harrison - and Ringo Starr.`; + return `The Beatles був англійським рок-гуртом, + cтвореним у Ліверпулі в 1960 році, до складу якого + входили Джон Леннон (John Lennon), Пол Маккартні (Paul McCartney), + Джордж Гаррісон (George Harrison) і Рінго Старр (Ringo Starr).`; } async function getAlbums() { - // Add a fake delay to make waiting noticeable. + // Додаємо штучну затримку, щоб очікування було помітним. await new Promise(resolve => { setTimeout(resolve, 3000); }); @@ -1725,9 +1725,9 @@ main { -When you pressed the button, the `Router` component rendered `ArtistPage` instead of `IndexPage`. A component inside `ArtistPage` suspended, so the closest Suspense boundary started showing the fallback. The closest Suspense boundary was near the root, so the whole site layout got replaced by `BigSpinner`. +Коли ви натиснули кнопку, компонент `Router` відрендерив `ArtistPage` замість `IndexPage`. Компонент всередині `ArtistPage` затриманий, тож найближча межа Suspense почала відображати запасний варіант. Найближча межа Suspense була біля корневого компонента, тому весь макет сайту було замінено на `BigSpinner`. -To prevent this, you can mark the navigation state update as a *Transition* with [`startTransition`:](/reference/react/startTransition) +Щоб запобігти цьому, ви можете відмітити оновлення стану навігації як *перехід*, використовуючи [`startTransition`:](/reference/react/startTransition) ```js {5,7} function Router() { @@ -1741,7 +1741,7 @@ function Router() { // ... ``` -This tells React that the state transition is not urgent, and it's better to keep showing the previous page instead of hiding any already revealed content. Now clicking the button "waits" for the `Biography` to load: +Це говорить React що перехід стану не є терміновим і краще продовжити показувати попередню сторінку, замість того, щоб ховати вже відображений вміст. Тепер натискання на кнопку "очікує", доки `Biography` завантажиться: @@ -1806,7 +1806,7 @@ function Router() { } function BigSpinner() { - return

      🌀 Loading...

      ; + return

      🌀 Завантаження...

      ; } ``` @@ -1815,7 +1815,7 @@ export default function Layout({ children }) { return (
      - Music Browser + Музичний Браузер
      {children} @@ -1829,7 +1829,7 @@ export default function Layout({ children }) { export default function IndexPage({ navigate }) { return ( ); } @@ -1869,11 +1869,11 @@ function AlbumsGlimmer() { ```js src/Albums.js hidden import { fetchData } from './data.js'; -// Note: this component is written using an experimental API -// that's not yet available in stable versions of React. +// Примітка: цей компонент створено з використанням експериментального API, +// яке ще не доступне в стабільних версіях React. -// For a realistic example you can follow today, try a framework -// that's integrated with Suspense, like Relay or Next.js. +// Для реалістичного прикладу, який ви можете спробувати сьогодні, скористайтеся фреймворком +// з інтегрованим Suspense, як-от Relay чи Next.js. export default function Albums({ artistId }) { const albums = use(fetchData(`/${artistId}/albums`)); @@ -1888,8 +1888,8 @@ export default function Albums({ artistId }) { ); } -// This is a workaround for a bug to get the demo running. -// TODO: replace with real implementation when the bug is fixed. +// Це тимчасове рішення для виправлення помилки, додане, щоб демонстрація працювала. +// TODO: замінити реальною реалізацією, коли помилку буде виправлено. function use(promise) { if (promise.status === 'fulfilled') { return promise.value; @@ -1917,11 +1917,11 @@ function use(promise) { ```js src/Biography.js hidden import { fetchData } from './data.js'; -// Note: this component is written using an experimental API -// that's not yet available in stable versions of React. +// Примітка: цей компонент створено з використанням експериментального API, +// яке ще не доступне в стабільних версіях React. -// For a realistic example you can follow today, try a framework -// that's integrated with Suspense, like Relay or Next.js. +// Для реалістичного прикладу, який ви можете спробувати сьогодні, скористайтеся фреймворком +// з інтегрованим Suspense, як-от Relay чи Next.js. export default function Biography({ artistId }) { const bio = use(fetchData(`/${artistId}/bio`)); @@ -1932,8 +1932,8 @@ export default function Biography({ artistId }) { ); } -// This is a workaround for a bug to get the demo running. -// TODO: replace with real implementation when the bug is fixed. +// Це тимчасове рішення для виправлення помилки, додане, щоб демонстрація працювала. +// TODO: замінити реальною реалізацією, коли помилку буде виправлено. function use(promise) { if (promise.status === 'fulfilled') { return promise.value; @@ -1969,9 +1969,9 @@ export default function Panel({ children }) { ``` ```js src/data.js hidden -// Note: the way you would do data fetching depends on -// the framework that you use together with Suspense. -// Normally, the caching logic would be inside a framework. +// Примітка: те, як ви будете отримувати дані, залежить +// від фреймворку, який ви використовуєте разом із Suspense. +// Зазвичай логіка кешування буде всередині фреймворку. let cache = new Map(); @@ -1993,19 +1993,19 @@ async function getData(url) { } async function getBio() { - // Add a fake delay to make waiting noticeable. + // Додаємо штучну затримку, щоб очікування було помітним. await new Promise(resolve => { setTimeout(resolve, 500); }); - return `The Beatles were an English rock band, - formed in Liverpool in 1960, that comprised - John Lennon, Paul McCartney, George Harrison - and Ringo Starr.`; + return `The Beatles був англійським рок-гуртом, + cтвореним у Ліверпулі в 1960 році, до складу якого + входили Джон Леннон (John Lennon), Пол Маккартні (Paul McCartney), + Джордж Гаррісон (George Harrison) і Рінго Старр (Ringo Starr).`; } async function getAlbums() { - // Add a fake delay to make waiting noticeable. + // Додаємо штучну затримку, щоб очікування було помітним. await new Promise(resolve => { setTimeout(resolve, 3000); }); @@ -2112,19 +2112,19 @@ main { -A Transition doesn't wait for *all* content to load. It only waits long enough to avoid hiding already revealed content. For example, the website `Layout` was already revealed, so it would be bad to hide it behind a loading spinner. However, the nested `Suspense` boundary around `Albums` is new, so the Transition doesn't wait for it. +Перехід не чекає на завантаження *всього* вмісту. Він лише чекає достатньо довго, щоб уникнути приховання вже відображеного вмісту. Для прикладу, `Layout` вебсайту вже було відображено, тому було би погано ховати його за спіннером завантаження. Проте, вкладена межа `Suspense` навколо `Albums` нова, тому перехід не чекає на неї. -Suspense-enabled routers are expected to wrap the navigation updates into Transitions by default. +Передбачається, що маршрутизатори з інтегрованим Suspense заздалегідь огортатимуть оновлення навігації в перехід. --- -### Indicating that a Transition is happening {/*indicating-that-a-transition-is-happening*/} +### Індикація переходу {/*indicating-that-a-transition-is-happening*/} -In the above example, once you click the button, there is no visual indication that a navigation is in progress. To add an indicator, you can replace [`startTransition`](/reference/react/startTransition) with [`useTransition`](/reference/react/useTransition) which gives you a boolean `isPending` value. In the example below, it's used to change the website header styling while a Transition is happening: +У прикладі зверху, як тільки ви натискаєте на кнопку, відсутній візуальний сигнал того, що відбувається навігація. Щоб додати індикатор, ви можете замінити [`startTransition`](/reference/react/startTransition) на [`useTransition`](/reference/react/useTransition), який дає вам булеве значення `isPending`. У прикладі нище, воно використовується, щоб змінити стилі хедеру вебсайту, доки відбувається перехід: @@ -2201,7 +2201,7 @@ export default function Layout({ children, isPending }) {
      - Music Browser + Музичний Браузер
      {children} @@ -2215,7 +2215,7 @@ export default function Layout({ children, isPending }) { export default function IndexPage({ navigate }) { return ( ); } @@ -2255,11 +2255,11 @@ function AlbumsGlimmer() { ```js src/Albums.js hidden import { fetchData } from './data.js'; -// Note: this component is written using an experimental API -// that's not yet available in stable versions of React. +// Примітка: цей компонент створено з використанням експериментального API, +// яке ще не доступне в стабільних версіях React. -// For a realistic example you can follow today, try a framework -// that's integrated with Suspense, like Relay or Next.js. +// Для реалістичного прикладу, який ви можете спробувати сьогодні, скористайтеся фреймворком +// з інтегрованим Suspense, як-от Relay чи Next.js. export default function Albums({ artistId }) { const albums = use(fetchData(`/${artistId}/albums`)); @@ -2274,8 +2274,8 @@ export default function Albums({ artistId }) { ); } -// This is a workaround for a bug to get the demo running. -// TODO: replace with real implementation when the bug is fixed. +// Це тимчасове рішення для виправлення помилки, додане, щоб демонстрація працювала. +// TODO: замінити реальною реалізацією, коли помилку буде виправлено. function use(promise) { if (promise.status === 'fulfilled') { return promise.value; @@ -2303,11 +2303,11 @@ function use(promise) { ```js src/Biography.js hidden import { fetchData } from './data.js'; -// Note: this component is written using an experimental API -// that's not yet available in stable versions of React. +// Примітка: цей компонент створено з використанням експериментального API, +// яке ще не доступне в стабільних версіях React. -// For a realistic example you can follow today, try a framework -// that's integrated with Suspense, like Relay or Next.js. +// Для реалістичного прикладу, який ви можете спробувати сьогодні, скористайтеся фреймворком +// з інтегрованим Suspense, як-от Relay чи Next.js. export default function Biography({ artistId }) { const bio = use(fetchData(`/${artistId}/bio`)); @@ -2318,8 +2318,8 @@ export default function Biography({ artistId }) { ); } -// This is a workaround for a bug to get the demo running. -// TODO: replace with real implementation when the bug is fixed. +// Це тимчасове рішення для виправлення помилки, додане, щоб демонстрація працювала. +// TODO: замінити реальною реалізацією, коли помилку буде виправлено. function use(promise) { if (promise.status === 'fulfilled') { return promise.value; @@ -2355,9 +2355,9 @@ export default function Panel({ children }) { ``` ```js src/data.js hidden -// Note: the way you would do data fetching depends on -// the framework that you use together with Suspense. -// Normally, the caching logic would be inside a framework. +// Примітка: те, як ви будете отримувати дані, залежить +// від фреймворку, який ви використовуєте разом із Suspense. +// Зазвичай логіка кешування буде всередині фреймворку. let cache = new Map(); @@ -2379,19 +2379,19 @@ async function getData(url) { } async function getBio() { - // Add a fake delay to make waiting noticeable. + // Додаємо штучну затримку, щоб очікування було помітним. await new Promise(resolve => { setTimeout(resolve, 500); }); - return `The Beatles were an English rock band, - formed in Liverpool in 1960, that comprised - John Lennon, Paul McCartney, George Harrison - and Ringo Starr.`; + return `The Beatles був англійським рок-гуртом, + cтвореним у Ліверпулі в 1960 році, до складу якого + входили Джон Леннон (John Lennon), Пол Маккартні (Paul McCartney), + Джордж Гаррісон (George Harrison) і Рінго Старр (Ringo Starr).`; } async function getAlbums() { - // Add a fake delay to make waiting noticeable. + // Додаємо штучну затримку, щоб очікування було помітним. await new Promise(resolve => { setTimeout(resolve, 3000); }); @@ -2500,27 +2500,27 @@ main { --- -### Resetting Suspense boundaries on navigation {/*resetting-suspense-boundaries-on-navigation*/} +### Скидання меж Suspense під час навігації {/*resetting-suspense-boundaries-on-navigation*/} -During a Transition, React will avoid hiding already revealed content. However, if you navigate to a route with different parameters, you might want to tell React it is *different* content. You can express this with a `key`: +Під час переходу, React уникне приховання вже відображеного вмісту. Проте, якщо ви перейдете на маршрут з іншими параметрами, ви захочете сказати React, що це *інший* вміст. Ви можете досягнути цього з `key`: ```js ``` -Imagine you're navigating within a user's profile page, and something suspends. If that update is wrapped in a Transition, it will not trigger the fallback for already visible content. That's the expected behavior. +Уявіть, що ви переходите всередині сторінки профілю користувача, і щось затримується. Якщо те оновлення використовує перехід, воно не буде викликати запасний варіант для вже відображеного вмісту. Така поведінка є очікуваною. -However, now imagine you're navigating between two different user profiles. In that case, it makes sense to show the fallback. For example, one user's timeline is *different content* from another user's timeline. By specifying a `key`, you ensure that React treats different users' profiles as different components, and resets the Suspense boundaries during navigation. Suspense-integrated routers should do this automatically. +А тепер уявіть, що ви переходите між профілями двох різних користувачів. У такому випадку доцільно відображати запасний варіант. Наприклад, вміст стрічки одного користувача *відрізняється*, від стрічки іншого користувача. Вказуючи `key`, ви запевняєтеся, що React розглядає профілі різних користувачів як різні компоненти і скидає межу Suspense під час навігації. Маршрутизатори з інтегрованим Suspense повинні робити це автоматично. --- -### Providing a fallback for server errors and client-only content {/*providing-a-fallback-for-server-errors-and-client-only-content*/} +### Застосування запасного варіанту для серверних помилок та вмісту, що опрацьовується тільки на стороні клієнта {/*providing-a-fallback-for-server-errors-and-client-only-content*/} -If you use one of the [streaming server rendering APIs](/reference/react-dom/server) (or a framework that relies on them), React will also use your `` boundaries to handle errors on the server. If a component throws an error on the server, React will not abort the server render. Instead, it will find the closest `` component above it and include its fallback (such as a spinner) into the generated server HTML. The user will see a spinner at first. +Якщо ви використовуєте якийсь з [API для потокового рендеру на стороні сервера](/reference/react-dom/server) (або фреймворк, що покладається на них), React також використовуватими вашу межу ``, щоб обробляти помилки на стороні сервера. Якщо компонент видає помилку на стороні сервера, React не відмінить серверний рендеринг. Натомість, він знайде найближчий компонент `` вище нього й додасть його запасний варіант (наприклад спіннер) у згенерований сервером HTML. Спочатку користувач побачить спіннер. -On the client, React will attempt to render the same component again. If it errors on the client too, React will throw the error and display the closest [error boundary.](/reference/react/Component#static-getderivedstatefromerror) However, if it does not error on the client, React will not display the error to the user since the content was eventually displayed successfully. +На стороні клієнта, React спробує відрендерити той же компонент знову. Якщо в ньому виникає помилка й на стороні клієнта, React видасть помилку і відобразить найближчу [границю помилки.](/reference/react/Component#static-getderivedstatefromerror) Проте, якщо він не видає помилки на стороні клієнта, React не буде відображати користувачу помилку, тому що вміст усе ж був відображений коректно. -You can use this to opt out some components from rendering on the server. To do this, throw an error in the server environment and then wrap them in a `` boundary to replace their HTML with fallbacks: +Ви можете використати це, щоб виключити деякі компоненти з рендерингу на стороні сервера. Щоб зробити це, видайте помилку в серверному оточенні й обгорніть ці компоненти в межу ``, щоб замінити їхній HTML запасним варіантом: ```js }> @@ -2529,35 +2529,35 @@ You can use this to opt out some components from rendering on the server. To do function Chat() { if (typeof window === 'undefined') { - throw Error('Chat should only render on the client.'); + throw Error('Чат повинен рендеритися тільки на стороні клієнта.'); } // ... } ``` -The server HTML will include the loading indicator. It will be replaced by the `Chat` component on the client. +Відрендерений на стороні сервера HTML включатиме лише індикатор завантаження. Його буде замінено компонентом `Chat` на стороні клієнта. --- -## Troubleshooting {/*troubleshooting*/} +## Усунення неполадок {/*troubleshooting*/} -### How do I prevent the UI from being replaced by a fallback during an update? {/*preventing-unwanted-fallbacks*/} +### Як я можу запобігти заміні UI запасним варіантом під час оновлення? {/*preventing-unwanted-fallbacks*/} -Replacing visible UI with a fallback creates a jarring user experience. This can happen when an update causes a component to suspend, and the nearest Suspense boundary is already showing content to the user. +Заміна видимого UI запасним варіантом спричиняє неприємний користувацький досвід. Це стається, коли оновлення спричиняє затримку компонента, а найближчий Suspense вже показує вміст користувачу. -To prevent this from happening, [mark the update as non-urgent using `startTransition`](#preventing-already-revealed-content-from-hiding). During a Transition, React will wait until enough data has loaded to prevent an unwanted fallback from appearing: +Щоб запобігти цьому, [відмітьте оновлення нетерміновим, використовуючи `startTransition`](#preventing-already-revealed-content-from-hiding). Під час переходу, React зачекає на завантаження даних, щоб запобігти відображенню небажаного запасного варіанту: ```js {2-3,5} function handleNextPageClick() { - // If this update suspends, don't hide the already displayed content + // Якщо це оновлення затримається, уже відображений вміст не буде сховано startTransition(() => { setCurrentPage(currentPage + 1); }); } ``` -This will avoid hiding existing content. However, any newly rendered `Suspense` boundaries will still immediately display fallbacks to avoid blocking the UI and let the user see the content as it becomes available. +Це допоможе уникнути приховання вже існуючого вмісту. Однак, будь-яка наново відрендерена межа `Suspense`, усе ще відображатиме запасний варіант, щоб уникнути блокування UI і дасть змогу користувачу бачити вміст як тільки він стане доступним. -**React will only prevent unwanted fallbacks during non-urgent updates**. It will not delay a render if it's the result of an urgent update. You must opt in with an API like [`startTransition`](/reference/react/startTransition) or [`useDeferredValue`](/reference/react/useDeferredValue). +**React запобігатиме небажаним запасним варіантам лише під час нетермінових оновлень**. Він не затримуватиме рендеринг, якщо це результат термінового оновлення. Ви повинні увімкнути це з API, наприклад, [`startTransition`](/reference/react/startTransition) або [`useDeferredValue`](/reference/react/useDeferredValue). -If your router is integrated with Suspense, it should wrap its updates into [`startTransition`](/reference/react/startTransition) automatically. +Якщо у ваш маршрутизатор інтегровано Suspense, він повинен огортати оновлення у [`startTransition`](/reference/react/startTransition) автоматично. \ No newline at end of file