From aa361527c283ced3f9ce045a4d15a81e36f679df Mon Sep 17 00:00:00 2001 From: Dmytro Date: Sun, 5 Oct 2025 18:45:50 +0200 Subject: [PATCH] feat: translate preserving-and-resetting-state page --- .../learn/preserving-and-resetting-state.md | 438 +++++++++--------- src/sidebarLearn.json | 2 +- 2 files changed, 220 insertions(+), 220 deletions(-) diff --git a/src/content/learn/preserving-and-resetting-state.md b/src/content/learn/preserving-and-resetting-state.md index d35071845..67b142996 100644 --- a/src/content/learn/preserving-and-resetting-state.md +++ b/src/content/learn/preserving-and-resetting-state.md @@ -1,28 +1,28 @@ --- -title: Preserving and Resetting State +title: Збереження та скидання стану --- -State is isolated between components. React keeps track of which state belongs to which component based on their place in the UI tree. You can control when to preserve state and when to reset it between re-renders. +Стан ізольований між компонентами. React відстежує, який стан належить якому компоненту, виходячи з їх місця в дереві інтерфейсу користувача. Ви можете керувати тим, коли зберігати стан, а коли скидати його між рендерами. -* When React chooses to preserve or reset the state -* How to force React to reset component's state -* How keys and types affect whether the state is preserved +* Коли React зберігає або скидає стан +* Як примусити React скинути стан компоненти +* Як ключі та типи впливають на збереження стану -## State is tied to a position in the render tree {/*state-is-tied-to-a-position-in-the-tree*/} +## Стан прив'язаний до позиції у дереві рендерингу {/*state-is-tied-to-a-position-in-the-tree*/} -React builds [render trees](learn/understanding-your-ui-as-a-tree#the-render-tree) for the component structure in your UI. +React будує [дерева рендерингу](learn/understanding-your-ui-as-a-tree#the-render-tree) для структури компонентів у вашому інтерфейсі. -When you give a component state, you might think the state "lives" inside the component. But the state is actually held inside React. React associates each piece of state it's holding with the correct component by where that component sits in the render tree. +Коли ви надаєте компоненту стан, ви можете подумати, що стан "живе" всередині компонента. Але насправді стан зберігається всередині React. React пов'язує кожен фрагмент стану, який він утримує, з відповідним компонентом, по тому де цей компонент знаходиться в дереві рендерингу. -Here, there is only one `` JSX tag, but it's rendered at two different positions: +В даному прикладі використовується тільки один JSX тег ``, але він рендериться в двох різних позиціях. @@ -56,7 +56,7 @@ function Counter() { >

{score}

); @@ -70,7 +70,7 @@ label { } .counter { - width: 100px; + width: 150px; text-align: center; border: 1px solid gray; border-radius: 4px; @@ -86,23 +86,23 @@ label {
-Here's how these look as a tree: +Ось як вони відображаються у вигляді дерева: - + -React tree +React дерево -**These are two separate counters because each is rendered at its own position in the tree.** You don't usually have to think about these positions to use React, but it can be useful to understand how it works. +**Це два окремі лічильника, оскільки кожен із них рендериться на своїй позиції в дереві.** Зазвичай вам не потрібно думати про ці позиції щоб використовувати React, але розуміння того, як це працює, може бути корисним. -In React, each component on the screen has fully isolated state. For example, if you render two `Counter` components side by side, each of them will get its own, independent, `score` and `hover` states. +В React, кожен компонент на екрані має повністю ізольований стан. Для прикладу, якщо ви рендерите два компоненти `Counter` поруч, кожен з них отримає свої власні, незалежні стани `score` та `hover`. -Try clicking both counters and notice they don't affect each other: +Спробуйте натиснути на обидва лічильника і ви помітите, що вони не впливають один на одного: @@ -135,7 +135,7 @@ function Counter() { >

{score}

); @@ -144,7 +144,7 @@ function Counter() { ```css .counter { - width: 100px; + width: 150px; text-align: center; border: 1px solid gray; border-radius: 4px; @@ -160,21 +160,21 @@ function Counter() {
-As you can see, when one counter is updated, only the state for that component is updated: +Як ви можете бачити, коли один лічильник оновлюється, тільки стан тієї компоненти оновлюється: - + -Updating state +Оновлення стану -React will keep the state around for as long as you render the same component at the same position in the tree. To see this, increment both counters, then remove the second component by unchecking "Render the second counter" checkbox, and then add it back by ticking it again: +React зберігатиме цей стан доти, доки ви рендерите той самий компонент у тій самій позиції в дереві. Щоб побачити це, збільште обидва лічильника, потім видаліть другий компонент, знявши галочку "Рендерити другий лічильник", а потім додайте його назад, поставивши галочку знову: @@ -195,7 +195,7 @@ export default function App() { setShowB(e.target.checked) }} /> - Render the second counter + Рендерити другий лічильник ); @@ -218,7 +218,7 @@ function Counter() { >

{score}

); @@ -232,7 +232,7 @@ label { } .counter { - width: 100px; + width: 150px; text-align: center; border: 1px solid gray; border-radius: 4px; @@ -248,35 +248,35 @@ label {
-Notice how the moment you stop rendering the second counter, its state disappears completely. That's because when React removes a component, it destroys its state. +Зверніть увагу, що як тільки ви зупиняєте рендеринг другого лічильника, його стан повністю зникає. Це тому, що коли React видаляє компонент, він знищує його стан. - + -Deleting a component +Видалення компонента -When you tick "Render the second counter", a second `Counter` and its state are initialized from scratch (`score = 0`) and added to the DOM. +Коли ви вибираєте "Рендерити другий лічильник", другий `Counter` і його стан ініціалізуються з нуля (`рахунок = 0`) і додаються до DOM. - + -Adding a component +Додавання компонента -**React preserves a component's state for as long as it's being rendered at its position in the UI tree.** If it gets removed, or a different component gets rendered at the same position, React discards its state. +**React зберігає стан компоненти до тих пір, поки компонент рендериться на своєму місці в дереві інтерфейсу користувача.** Якщо його буде видалено, або на тому ж місці буде відрендерено інший компонент, React очистить його стейт. -## Same component at the same position preserves state {/*same-component-at-the-same-position-preserves-state*/} +## Той самий компонент у тій самій позиції зберігає стан {/*same-component-at-the-same-position-preserves-state*/} -In this example, there are two different `` tags: +У цьому прикладі є два різних `` теги: @@ -300,7 +300,7 @@ export default function App() { setIsFancy(e.target.checked) }} /> - Use fancy styling + Використати вишукану стилізацію ); @@ -326,7 +326,7 @@ function Counter({ isFancy }) { >

{score}

); @@ -340,7 +340,7 @@ label { } .counter { - width: 100px; + width: 150px; text-align: center; border: 1px solid gray; border-radius: 4px; @@ -361,24 +361,24 @@ label {
-When you tick or clear the checkbox, the counter state does not get reset. Whether `isFancy` is `true` or `false`, you always have a `` as the first child of the `div` returned from the root `App` component: +Коли ви встановлюєте або знімаєте прапорець, стан лічильника не обнуляється. Не залежно від того, чи `isFancy` є `true` або `false`, у вас завжди є `` як перший дочірній елемент `div`, що повертається з кореневого компонента `App`. - + -Updating the `App` state does not reset the `Counter` because `Counter` stays in the same position +Оновлення стану `App` не обнуляє `Counter`, оскільки `Counter` залишається на тій самій позиції -It's the same component at the same position, so from React's perspective, it's the same counter. +Це той самий компонент на тій самій позиції, отже з точки зору React, це той самий лічильник. -Remember that **it's the position in the UI tree--not in the JSX markup--that matters to React!** This component has two `return` clauses with different `` JSX tags inside and outside the `if`: +Пам'ятайте, що **це позиція в дереві інтерфейсу користувача — не в JSX-розмітці — для React це важливо!** Цей компонент має два `return` пункти з різними `` JSX-тегами в середині та зовні `if`: @@ -399,7 +399,7 @@ export default function App() { setIsFancy(e.target.checked) }} /> - Use fancy styling + Використати вишукану стилізацію ); @@ -415,7 +415,7 @@ export default function App() { setIsFancy(e.target.checked) }} /> - Use fancy styling + Використати вишукану стилізацію ); @@ -441,7 +441,7 @@ function Counter({ isFancy }) { >

{score}

); @@ -455,7 +455,7 @@ label { } .counter { - width: 100px; + width: 150px; text-align: center; border: 1px solid gray; border-radius: 4px; @@ -476,15 +476,15 @@ label {
-You might expect the state to reset when you tick checkbox, but it doesn't! This is because **both of these `` tags are rendered at the same position.** React doesn't know where you place the conditions in your function. All it "sees" is the tree you return. +Ви можете очікувати, що стан буде обнулено, коли ви поставите галочку, але цього не станеться! Це тому, що **обидва теги `` рендеряться на тій самій позиції.** React не знає, де ви розміщуєте умови у вашій функції. Все, що він "бачить" — це дерево, що ви повертаєте. -In both cases, the `App` component returns a `
` with `` as a first child. To React, these two counters have the same "address": the first child of the first child of the root. This is how React matches them up between the previous and next renders, regardless of how you structure your logic. +В обох випадках, `App` компонент повертає `
` із `` як першим дочірнім елементом. Для React ці два лічильника мають однакову "адресу": перший нащадок першого нащадка кореня. Ось як React зіставляє їх між попереднім і наступним рендерингом, незалежно від того, як ви структуруєте свою логіку. -## Different components at the same position reset state {/*different-components-at-the-same-position-reset-state*/} +## Різні компоненти на тій самій позиції скидають стан {/*different-components-at-the-same-position-reset-state*/} -In this example, ticking the checkbox will replace `` with a `

`: +В цьому прикладі встановлення прапорця замінить `` на `

`: @@ -496,7 +496,7 @@ export default function App() { return (

{isPaused ? ( -

See you later!

+

Побачимось пізніше!

) : ( )} @@ -508,7 +508,7 @@ export default function App() { setIsPaused(e.target.checked) }} /> - Take a break + Зробіть перерву
); @@ -531,7 +531,7 @@ function Counter() { >

{score}

); @@ -545,7 +545,7 @@ label { } .counter { - width: 100px; + width: 150px; text-align: center; border: 1px solid gray; border-radius: 4px; @@ -561,13 +561,13 @@ label { -Here, you switch between _different_ component types at the same position. Initially, the first child of the `
` contained a `Counter`. But when you swapped in a `p`, React removed the `Counter` from the UI tree and destroyed its state. +Тут, ви переключаєте між _різними_ типами компонент на одній позиції. Початково перший дочірній елемент `
` містив `Counter`. Але коли ви замінили його на `p`, React видалив `Counter` з дерева інтерфейсу та знищив його стан. - + -When `Counter` changes to `p`, the `Counter` is deleted and the `p` is added +Коли `Counter` змінюється на `p`, то `Counter` видалено та `p` добавлено @@ -575,15 +575,15 @@ When `Counter` changes to `p`, the `Counter` is deleted and the `p` is added - + -When switching back, the `p` is deleted and the `Counter` is added +Коли перемикаємо назад, `p` видалено та `Counter` додано -Also, **when you render a different component in the same position, it resets the state of its entire subtree.** To see how this works, increment the counter and then tick the checkbox: +Крім того, **коли ви рендерите інший компонент у тому самому місці, це скидає стан усього його піддерева.** Щоб побачити, як це працює, збільште лічильник і потім встановіть прапорець: @@ -611,7 +611,7 @@ export default function App() { setIsFancy(e.target.checked) }} /> - Use fancy styling + Використати вишукану стилізацію
); @@ -637,7 +637,7 @@ function Counter({ isFancy }) { >

{score}

); @@ -651,7 +651,7 @@ label { } .counter { - width: 100px; + width: 150px; text-align: center; border: 1px solid gray; border-radius: 4px; @@ -672,13 +672,13 @@ label { -The counter state gets reset when you click the checkbox. Although you render a `Counter`, the first child of the `div` changes from a `div` to a `section`. When the child `div` was removed from the DOM, the whole tree below it (including the `Counter` and its state) was destroyed as well. +Стан лічильника скидається коли ви натискаєте на прапорець. Хоча ви рендерите `Counter`, перший дочірній елемент `div` змінюється з `div` на `section`. Коли дочірній елемент `div` було видалено з DOM, все дерево під ним (включаючи `Counter` та його стан) було також знищено. - + -When `section` changes to `div`, the `section` is deleted and the new `div` is added +Коли `section` змінюється на `div`, тоді `section` видаляється і новий `div` додається @@ -686,21 +686,21 @@ When `section` changes to `div`, the `section` is deleted and the new `div` is a - + -When switching back, the `div` is deleted and the new `section` is added +При перемиканні назад, `div` видаляється і нова `section` додається -As a rule of thumb, **if you want to preserve the state between re-renders, the structure of your tree needs to "match up"** from one render to another. If the structure is different, the state gets destroyed because React destroys state when it removes a component from the tree. +Як правила, **якщо ви хочете зберегти стан між повторними рендерами, структура вашого дерева повинна "збігатися"** від одного рендера до іншого. Якщо структура відрізняється, стан знищується, оскільки React знищує стан, коли видаляє компонент із дерева. -This is why you should not nest component function definitions. +Ось чому вам не варто вкладати визначення функційних компонент. -Here, the `MyTextField` component function is defined *inside* `MyComponent`: +Тут, `MyTextField` функційний компонент визначено *всередині* `MyComponent`: @@ -726,7 +726,7 @@ export default function MyComponent() { + }}>Натиснуто {counter} разів ); } @@ -735,13 +735,13 @@ export default function MyComponent() { -Every time you click the button, the input state disappears! This is because a *different* `MyTextField` function is created for every render of `MyComponent`. You're rendering a *different* component in the same position, so React resets all state below. This leads to bugs and performance problems. To avoid this problem, **always declare component functions at the top level, and don't nest their definitions.** +Кожного разу, коли ви натискаєте кнопку, стан введення зникає! Це відбувається тому, що *інша* `MyTextField` функція створюється на кожен рендер `MyComponent`. Ви рендерите *інший* компонент у тому самому місці, тому React скидає весь стан нижче. Це призводить до проблем та проблем із продуктивністю. Щоб уникнути цієї проблеми **завжди оголошуйте функційні компоненти на найвищому рівні і не вкладайте їхнє визначення.** -## Resetting state at the same position {/*resetting-state-at-the-same-position*/} +## Скидання стану в тому самому місці {/*resetting-state-at-the-same-position*/} -By default, React preserves state of a component while it stays at the same position. Usually, this is exactly what you want, so it makes sense as the default behavior. But sometimes, you may want to reset a component's state. Consider this app that lets two players keep track of their scores during each turn: +За замовчуванням, React зберігає стан компонента, поки він залишається на тому самому місці. Зазвичай, це саме те, що ви хочете, тому це має сенс як поведінка за замовчуванням. Але інколи вам може знадобитися скинути стан компонента. Розглянемо цей додаток, який дозволяє двом гравцям відстежувати свої результати під час кожного ходу: @@ -753,14 +753,14 @@ export default function Scoreboard() { return (
{isPlayerA ? ( - + ) : ( - + )}
); @@ -781,9 +781,9 @@ function Counter({ person }) { onPointerEnter={() => setHover(true)} onPointerLeave={() => setHover(false)} > -

{person}'s score: {score}

+

Рахунок {person}: {score}

); @@ -796,7 +796,7 @@ h1 { } .counter { - width: 100px; + width: 150px; text-align: center; border: 1px solid gray; border-radius: 4px; @@ -811,19 +811,19 @@ h1 { -Currently, when you change the player, the score is preserved. The two `Counter`s appear in the same position, so React sees them as *the same* `Counter` whose `person` prop has changed. +Зараз, коли ви змінюєте гравця, рахунок зберігається. Обидва `Counter` з'являються на одній і тій самій позиції, тому React сприймає їх як *один і той самий* `Counter`, у якого просто змінився проп `person`. -But conceptually, in this app they should be two separate counters. They might appear in the same place in the UI, but one is a counter for Taylor, and another is a counter for Sarah. +Але концептуально в цьому застосунку вони повинні бути двома окремими лічильниками. Вони можуть відображатися на одному й тому ж місці в інтерфейсі користувача, але один з них є лічильником для Тейлора, а інший — лічильником для Сари. -There are two ways to reset state when switching between them: +Є два способи скинути стан при перемиканні між ними: -1. Render components in different positions -2. Give each component an explicit identity with `key` +1. Рендерити компоненти на різних позиціях +2. Дати кожному компоненту явну ідентичність за допомогою `key` -### Option 1: Rendering a component in different positions {/*option-1-rendering-a-component-in-different-positions*/} +### Спосіб 1: Рендерити компонент в різних місцях {/*option-1-rendering-a-component-in-different-positions*/} -If you want these two `Counter`s to be independent, you can render them in two different positions: +Якщо ви хочете, щоб ці два `Counter`, були незалежними, вам потрібно рендерити їх в двох різних позиціях: @@ -835,15 +835,15 @@ export default function Scoreboard() { return (
{isPlayerA && - + } {!isPlayerA && - + }
); @@ -864,9 +864,9 @@ function Counter({ person }) { onPointerEnter={() => setHover(true)} onPointerLeave={() => setHover(false)} > -

{person}'s score: {score}

+

Рахунок {person}: {score}

); @@ -879,7 +879,7 @@ h1 { } .counter { - width: 100px; + width: 150px; text-align: center; border: 1px solid gray; border-radius: 4px; @@ -894,42 +894,42 @@ h1 {
-* Initially, `isPlayerA` is `true`. So the first position contains `Counter` state, and the second one is empty. -* When you click the "Next player" button the first position clears but the second one now contains a `Counter`. +* Спочатку `isPlayerA` дорівнює `true`. Тому перша позиція містить стан `Counter`, а друга — порожня. +* Коли ви натискаєте кнопку "Наступний гравець", перша позиція очищується, а друга тепер містить `Counter`. - + -Initial state +Початковий стан - + -Clicking "next" +Натискання "наступний" - + -Clicking "next" again +Натискання "наступний" знову -Each `Counter`'s state gets destroyed each time it's removed from the DOM. This is why they reset every time you click the button. +Стан кожного `Counter` знищується щоразу, коли його видаляють із DOM. Саме тому вони скидаються щоразу, коли ви натискаєте кнопку. -This solution is convenient when you only have a few independent components rendered in the same place. In this example, you only have two, so it's not a hassle to render both separately in the JSX. +Це рішення зручне, коли у вас лише кілька незалежних компонент, які рендеряться на одному місці. У цьому прикладі їх лише два, тому не складно рендерити обидві окремо в JSX. -### Option 2: Resetting state with a key {/*option-2-resetting-state-with-a-key*/} +### Спосіб 2: Скидання стану за допомогою ключа {/*option-2-resetting-state-with-a-key*/} -There is also another, more generic, way to reset a component's state. +Існує також інший, більш загальний спосіб скидання стану компонента. -You might have seen `key`s when [rendering lists.](/learn/rendering-lists#keeping-list-items-in-order-with-key) Keys aren't just for lists! You can use keys to make React distinguish between any components. By default, React uses order within the parent ("first counter", "second counter") to discern between components. But keys let you tell React that this is not just a *first* counter, or a *second* counter, but a specific counter--for example, *Taylor's* counter. This way, React will know *Taylor's* counter wherever it appears in the tree! +Ви могли бачити `key` коли [рендерите списки.](/learn/rendering-lists#keeping-list-items-in-order-with-key) Ключі не тільки для списків! Ви можете використовувати ключі, щоб React розрізняв будь-які компоненти. За замовчуванням React використовує порядок в середині батьківського елемента ("перший лічильник", "другий лічильник"), щоб розрізняти компоненти. Але ключі дають можливість вам сказати до React, що це не просто *перший* лічильник або *другий* лічильник а конкретний лічильник — для прикладу, лічильник *Тайлера*. Таким чином, React буде знати лічильник *Тайлера* будь-коли він з'явиться в дереві! -In this example, the two ``s don't share state even though they appear in the same place in JSX: +В цьому прикладі, два `` не поширюють стан, хоча вони появляються в одному місці в JSX: @@ -941,14 +941,14 @@ export default function Scoreboard() { return (
{isPlayerA ? ( - + ) : ( - + )}
); @@ -969,9 +969,9 @@ function Counter({ person }) { onPointerEnter={() => setHover(true)} onPointerLeave={() => setHover(false)} > -

{person}'s score: {score}

+

Рахунок {person}: {score}

); @@ -984,7 +984,7 @@ h1 { } .counter { - width: 100px; + width: 150px; text-align: center; border: 1px solid gray; border-radius: 4px; @@ -999,29 +999,29 @@ h1 {
-Switching between Taylor and Sarah does not preserve the state. This is because **you gave them different `key`s:** +Переключення між станом Тайлера і Сари не зберігає стан. Це тому що **ви дали їм різні `key`:** ```js {isPlayerA ? ( - + ) : ( - + )} ``` -Specifying a `key` tells React to use the `key` itself as part of the position, instead of their order within the parent. This is why, even though you render them in the same place in JSX, React sees them as two different counters, and so they will never share state. Every time a counter appears on the screen, its state is created. Every time it is removed, its state is destroyed. Toggling between them resets their state over and over. +Вказуючи `key` ви кажете React використовувати `key` як частину місця розташування замість його власного порядку в середині батьківського елемента. Саме через це, навіть якщо ви рендерите їх в одному місці в JSX, React бачить їх як два різних лічильника, саме тому вони ніколи не поширюватимуть стан. Кожного разу коли лічильник появляється на екрані, його стан створюється. Кожен раз коли він видалений, його стан знищується. Переключення між ними скидає їхній стан знову і знову. -Remember that keys are not globally unique. They only specify the position *within the parent*. +Пам'ятайте, що ключі не є глобально унікальними. Вони лише визначають позицію *в середині батьківського елемента*. -### Resetting a form with a key {/*resetting-a-form-with-a-key*/} +### Скидання форми за допомогою ключа {/*resetting-a-form-with-a-key*/} -Resetting state with a key is particularly useful when dealing with forms. +Скидання стану за допомогою ключа є особливо корисне при роботі з формами. -In this chat app, the `` component contains the text input state: +В цьому чат-застосунку компонент `` містить стан поля введення тексту: @@ -1045,9 +1045,9 @@ export default function Messenger() { } const contacts = [ - { id: 0, name: 'Taylor', email: 'taylor@mail.com' }, - { id: 1, name: 'Alice', email: 'alice@mail.com' }, - { id: 2, name: 'Bob', email: 'bob@mail.com' } + { id: 0, name: 'Тайлер', email: 'taylor@mail.com' }, + { id: 1, name: 'Аліса', email: 'alice@mail.com' }, + { id: 2, name: 'Боб', email: 'bob@mail.com' } ]; ``` @@ -1084,11 +1084,11 @@ export default function Chat({ contact }) {