diff --git a/src/content/learn/state-as-a-snapshot.md b/src/content/learn/state-as-a-snapshot.md index 503b0abb4..d64020e69 100644 --- a/src/content/learn/state-as-a-snapshot.md +++ b/src/content/learn/state-as-a-snapshot.md @@ -1,27 +1,27 @@ --- -title: State as a Snapshot +title: Состояние как снимок --- -State variables might look like regular JavaScript variables that you can read and write to. However, state behaves more like a snapshot. Setting it does not change the state variable you already have, but instead triggers a re-render. +На первый взгляд, переменные состояния выглядят как обычные JavaScript-переменные, с которыми вы можете проводить операции чтения и записи. Однако, состояние больше похоже на снимок, чем на классическую переменную. Установка нового значения переменной состояния не изменяет напрямую текущее состояние, но при этом инициирует повторный рендер. -* How setting state triggers re-renders -* When and how state updates -* Why state does not update immediately after you set it -* How event handlers access a "snapshot" of the state +* Как установка состояния запускает повторный рендер +* Каким образом происходит обновление состояния +* Почему не происходит моментального обновления состояния после того, как вы задали новое значение переменной +* Как обработчики событий получают доступ к "снимку" состояния -## Setting state triggers renders {/*setting-state-triggers-renders*/} +## Установка состояния запускает рендер {/*setting-state-triggers-renders*/} -You might think of your user interface as changing directly in response to the user event like a click. In React, it works a little differently from this mental model. On the previous page, you saw that [setting state requests a re-render](/learn/render-and-commit#step-1-trigger-a-render) from React. This means that for an interface to react to the event, you need to *update the state*. +Вы можете думать, что события, которые появляются от взаимодействия пользователя с интерфейсом (например, после нажатия кнопки), должны моментально изменять UI. На самом деле, в React это работает немного по-другому. На предыдущей странице вы видели, что [изменение состояния запрашивает повторный рендер](/learn/render-and-commit#step-1-trigger-a-render). Это значит, чтобы интерфейс смог отреагировать на событие, необходимо *обновить состояние*. -In this example, when you press "send", `setIsSent(true)` tells React to re-render the UI: +Рассмотрим пример кода ниже. Когда вы нажимаете на кнопку "Отправить", `setIsSent(true)` сообщает React о необходимости повторного рендера UI: @@ -30,9 +30,9 @@ import { useState } from 'react'; export default function Form() { const [isSent, setIsSent] = useState(false); - const [message, setMessage] = useState('Hi!'); + const [message, setMessage] = useState('Привет!'); if (isSent) { - return

Your message is on its way!

+ return

Ваше сообщение уже в пути!

} return (
{ @@ -45,7 +45,7 @@ export default function Form() { value={message} onChange={e => setMessage(e.target.value)} /> - +
); } @@ -61,43 +61,43 @@ label, textarea { margin-bottom: 10px; display: block; }
-Here's what happens when you click the button: +Итак, что же происходит, когда вы нажимаете на кнопку: -1. The `onSubmit` event handler executes. -2. `setIsSent(true)` sets `isSent` to `true` and queues a new render. -3. React re-renders the component according to the new `isSent` value. +1. Выполняется обработчик события `onSubmit`. +2. `setIsSent(true)` устанавливает `isSent` значение `true` и добавляет в очередь новый рендер. +3. React вновь рендерит компонент, опираясь на новое значение `isSent`. -Let's take a closer look at the relationship between state and rendering. +Давайте более детально рассмотрим взаимосвязь между состоянием и рендером. -## Rendering takes a snapshot in time {/*rendering-takes-a-snapshot-in-time*/} +## Рендер создаёт моментальный снимок во времени {/*rendering-takes-a-snapshot-in-time*/} -["Rendering"](/learn/render-and-commit#step-2-react-renders-your-components) means that React is calling your component, which is a function. The JSX you return from that function is like a snapshot of the UI in time. Its props, event handlers, and local variables were all calculated **using its state at the time of the render.** +["Рендер"](/learn/render-and-commit#step-2-react-renders-your-components) означает, что React вызывает ваш компонент как функцию. JSX, который вы получаете из данной функции, подобен снимку UI в определённый момент времени. При этом пропсы, обработчики событий и локальные переменные компонента были рассчитаны, **опираясь на состояние компонента во время рендера**. -Unlike a photograph or a movie frame, the UI "snapshot" you return is interactive. It includes logic like event handlers that specify what happens in response to inputs. React updates the screen to match this snapshot and connects the event handlers. As a result, pressing a button will trigger the click handler from your JSX. +Если сравнивать с фотографией или кадром из фильма, снимок UI имеет интерактивность. Снимок включает в себя обработчики событий, которые определяют, что будет происходить в ответ на пользовательские действия. React обновляет интерфейс в соответствии со снимком и подключает обработчики событий. Например, нажатие на кнопку вызовет обработчик клика из вашего JSX. -When React re-renders a component: +Когда React повторно рендерит компонент: -1. React calls your function again. -2. Your function returns a new JSX snapshot. -3. React then updates the screen to match the snapshot you've returned. +1. React вызывает ваш компонент как функцию. +2. Функция возвращает новый снимок JSX. +3. Далее React обновляет экран в соответствии с данными, которые были возвращены со снимком JSX. - - - + + + -As a component's memory, state is not like a regular variable that disappears after your function returns. State actually "lives" in React itself--as if on a shelf!--outside of your function. When React calls your component, it gives you a snapshot of the state for that particular render. Your component returns a snapshot of the UI with a fresh set of props and event handlers in its JSX, all calculated **using the state values from that render!** +Если рассматривать состояние как память компонента, состояние не похоже на обычную переменную, которая исчезает после завершения работы функции. На самом деле, состояние продолжает "жить" в React вне вашей функции и будто находится на специальной полке в памяти. Когда React вызывает ваш компонент, он отдаёт вам снимок состояния для конкретного рендера. Ваш компонент возвращает снимок UI с актуальными пропсами, обработчиками событий в JSX. Все это рассчитано **с использованием значений состояния из этого рендера**. - - - + + + -Here's a little experiment to show you how this works. In this example, you might expect that clicking the "+3" button would increment the counter three times because it calls `setNumber(number + 1)` three times. +Посмотрим на небольшой пример и изучим его работу. Вы можете ожидать, что нажимая на кнопку "+3", произойдёт обновление счётчика ровно три раза, так как трижды происходит вызов `setNumber(number + 1)` -See what happens when you click the "+3" button: +Нажмём на кнопку "+3" и посмотрим на результат: @@ -127,9 +127,9 @@ h1 { display: inline-block; margin: 10px; width: 30px; text-align: center; } -Notice that `number` only increments once per click! +Обратите внимание, `number` увеличивается только один раз за клик! -**Setting state only changes it for the *next* render.** During the first render, `number` was `0`. This is why, in *that render's* `onClick` handler, the value of `number` is still `0` even after `setNumber(number + 1)` was called: +**Установка состояния изменяет его только для *следующего* рендера**. Во время первого рендера значение `number` равно `0`. Вот почему в обработчике `onClick` *этого текущего рендера* значение `number` по-прежнему равно `0`, даже после вызова `setNumber(number + 1)`: ```js ``` -Here is what this button's click handler tells React to do: +Обработчик кнопки сообщает React делать следующее: -1. `setNumber(number + 1)`: `number` is `0` so `setNumber(0 + 1)`. - - React prepares to change `number` to `1` on the next render. -2. `setNumber(number + 1)`: `number` is `0` so `setNumber(0 + 1)`. - - React prepares to change `number` to `1` on the next render. -3. `setNumber(number + 1)`: `number` is `0` so `setNumber(0 + 1)`. - - React prepares to change `number` to `1` on the next render. +1. `setNumber(number + 1)`: `number` равно `0`, вызывай `setNumber(0 + 1)`. + - React готовится изменить `number` на `1` для следующего рендера. +2. `setNumber(number + 1)`: `number` равно `0`, вызывай`setNumber(0 + 1)`. + - React готовится изменить `number` на `1` для следующего рендера. +3. `setNumber(number + 1)`: `number` равно `0`, вызывай`setNumber(0 + 1)`. + - React готовится изменить `number` на `1` для следующего рендера. -Even though you called `setNumber(number + 1)` three times, in *this render's* event handler `number` is always `0`, so you set the state to `1` three times. This is why, after your event handler finishes, React re-renders the component with `number` equal to `1` rather than `3`. +Даже если вы вызовите `setNumber(number + 1)` трижды в обработчике события, *в этом текущем рендере* `number` всегда будет равно `0`, вы просто трижды установите `number` значение `1`. Вот почему после завершения работы обработчика события React отображает компонент с `number` равным `1`, а не `3`. -You can also visualize this by mentally substituting state variables with their values in your code. Since the `number` state variable is `0` for *this render*, its event handler looks like this: +Вы также можете визуализировать это, мысленно заменяя значения переменных состояния в своём коде. Поскольку переменная состояния `number` равна `0`, для *этого рендера* обработчик клика выглядит следующим образом: ```js ``` -For the next render, `number` is `1`, so *that render's* click handler looks like this: +Для следующего рендера, значение `number` равно `1`, для *этого рендера* обработчик клика будет выглядеть: ```js ``` -This is why clicking the button again will set the counter to `2`, then to `3` on the next click, and so on. +Нажатие на кнопку установит `number` значение `2`, при следующем нажатии `3` и так далее. -## State over time {/*state-over-time*/} +## Состояние с течением времени {/*state-over-time*/} -Well, that was fun. Try to guess what clicking this button will alert: +Было весело! Теперь попробуйте угадать, какое оповещение появится после нажатия кнопки в следующем примере: @@ -203,14 +203,14 @@ h1 { display: inline-block; margin: 10px; width: 30px; text-align: center; } -If you use the substitution method from before, you can guess that the alert shows "0": +Если вы воспользуетесь методом подстановки, как было показано ранее, вероятно, ваш ответ будет "0": ```js setNumber(0 + 5); alert(0); ``` -But what if you put a timer on the alert, so it only fires _after_ the component re-rendered? Would it say "0" or "5"? Have a guess! +А что, если вы установите таймер для вашего предупреждения `alert`, дождётесь первого вызова `setNumber(number + 5)` и повторного рендера? Каким будет значение: `0` или `5`, попробуйте угадать! @@ -241,7 +241,7 @@ h1 { display: inline-block; margin: 10px; width: 30px; text-align: center; } -Surprised? If you use the substitution method, you can see the "snapshot" of the state passed to the alert. +Удивлены? Если вы воспользуетесь методом подстановки, вы сможете увидеть «снимок» состояния, переданного в `alert`. ```js setNumber(0 + 5); @@ -250,16 +250,16 @@ setTimeout(() => { }, 3000); ``` -The state stored in React may have changed by the time the alert runs, but it was scheduled using a snapshot of the state at the time the user interacted with it! +Состояние, которое хранится в React, могло измениться к моменту запуска оповещения `alert`, но оно было запланировано с использованием снимка состояния на момент взаимодействия с ним пользователя! -**A state variable's value never changes within a render,** even if its event handler's code is asynchronous. Inside *that render's* `onClick`, the value of `number` continues to be `0` even after `setNumber(number + 5)` was called. Its value was "fixed" when React "took the snapshot" of the UI by calling your component. +**Значения переменных состояния никогда не изменяются без рендера**, даже если в обработчике события есть асинхронный код. Внутри `onClick` *в текущем рендере*, значение `number` продолжает быть `0`, даже после вызова `setNumber(number + 5)`. Значение состояния было "зафиксировано" в моменте, когда React создавал снимок UI при вызове компонента. -Here is an example of how that makes your event handlers less prone to timing mistakes. Below is a form that sends a message with a five-second delay. Imagine this scenario: +Рассмотрим пример, как это правило делает обработчики событий более устойчивыми к ошибкам синхронизации. Ниже представлена форма, которая отправляет сообщение с задержкой в 5 секунд. Представьте себе сценарий: -1. You press the "Send" button, sending "Hello" to Alice. -2. Before the five-second delay ends, you change the value of the "To" field to "Bob". +1. Вы нажимаете на кнопку "Отправить", отправляя "Привет" для Элис. +2. До того, как истечёт пятисекундный таймер, вы успеете поменять значение поля "Кому" на "Бобу". -What do you expect the `alert` to display? Would it display, "You said Hello to Alice"? Or would it display, "You said Hello to Bob"? Make a guess based on what you know, and then try it: +Какой результат вы ожидаете увидеть в `alert`? Будет отображено "Вы сказали Привет Элис" или же "Вы сказали Привет Бобу"? Попробуйте предположить, опираясь на знания, которые вы получили ранее, после запустите пример и посмотрите результат: @@ -267,25 +267,25 @@ What do you expect the `alert` to display? Would it display, "You said Hello to import { useState } from 'react'; export default function Form() { - const [to, setTo] = useState('Alice'); - const [message, setMessage] = useState('Hello'); + const [to, setTo] = useState('Элис'); + const [message, setMessage] = useState('Привет'); function handleSubmit(e) { e.preventDefault(); setTimeout(() => { - alert(`You said ${message} to ${to}`); + alert(`Вы сказали ${message} ${to}`); }, 5000); } return (