From ea46188e645c9900f02bafef4f99e26f14f27ea7 Mon Sep 17 00:00:00 2001 From: fpetrakov Date: Fri, 21 Apr 2023 19:59:29 +0300 Subject: [PATCH 001/233] beep --- src/content/reference/react/components.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/content/reference/react/components.md b/src/content/reference/react/components.md index 7ce3fab63..f8a96fd66 100644 --- a/src/content/reference/react/components.md +++ b/src/content/reference/react/components.md @@ -1,24 +1,24 @@ --- -title: "Built-in React Components" +title: "Встроенные реакт-компоненты" --- -React exposes a few built-in components that you can use in your JSX. +Реакт из коробки предоставляет несколько компонентов. --- -## Built-in components {/*built-in-components*/} +## Встроенные компоненты {/*built-in-components*/} -* [``](/reference/react/Fragment), alternatively written as `<>...`, lets you group multiple JSX nodes together. -* [``](/reference/react/Profiler) lets you measure rendering performance of a React tree programmatically. -* [``](/reference/react/Suspense) lets you display a fallback while the child components are loading. -* [``](/reference/react/StrictMode) enables extra development-only checks that help you find bugs early. +* [``](/reference/react/Fragment), или `<>...`, объединяет несколько JSX узлов вместе. +* [``](/reference/react/Profiler) измеряет производительность рендера компонентов. +* [``](/reference/react/Suspense) отображает заглушку, пока загружаются дочерние компоненты. +* [``](/reference/react/StrictMode) включает дополнительные проверки в режиме разработки, они помогают находить баги раньше. --- -## Your own components {/*your-own-components*/} +## Ваши компоненты {/*your-own-components*/} -You can also [define your own components](/learn/your-first-component) as JavaScript functions. +Вы тоже можете [создавать свои компоненты](/learn/your-first-component), используя JavaScript функции. From 48ee58342ff81fa13bd549ee2ceeb06f563761f5 Mon Sep 17 00:00:00 2001 From: fpetrakov Date: Fri, 21 Apr 2023 20:01:04 +0300 Subject: [PATCH 002/233] fix --- src/content/reference/react/components.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/reference/react/components.md b/src/content/reference/react/components.md index f8a96fd66..cc159bee1 100644 --- a/src/content/reference/react/components.md +++ b/src/content/reference/react/components.md @@ -21,4 +21,4 @@ title: "Встроенные реакт-компоненты" ## Ваши компоненты {/*your-own-components*/} -Вы тоже можете [создавать свои компоненты](/learn/your-first-component), используя JavaScript функции. +Вы также можете [создавать свои компоненты](/learn/your-first-component), используя JavaScript функции. From 9c67160a1dd0561da4364769ba078dc58018f197 Mon Sep 17 00:00:00 2001 From: fpetrakov Date: Fri, 21 Apr 2023 20:08:06 +0300 Subject: [PATCH 003/233] translate sidebar --- src/sidebarReference.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sidebarReference.json b/src/sidebarReference.json index f009cca0e..6ac7b51ee 100644 --- a/src/sidebarReference.json +++ b/src/sidebarReference.json @@ -73,7 +73,7 @@ ] }, { - "title": "Components", + "title": "Компоненты", "path": "/reference/react/components", "routes": [ { From 03855fb47fd356a1dfee40e3bede9c7104165441 Mon Sep 17 00:00:00 2001 From: fpetrakov Date: Fri, 21 Apr 2023 20:11:33 +0300 Subject: [PATCH 004/233] remove useless word --- src/content/reference/react/components.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/reference/react/components.md b/src/content/reference/react/components.md index cc159bee1..dac1b4021 100644 --- a/src/content/reference/react/components.md +++ b/src/content/reference/react/components.md @@ -12,7 +12,7 @@ title: "Встроенные реакт-компоненты" ## Встроенные компоненты {/*built-in-components*/} -* [``](/reference/react/Fragment), или `<>...`, объединяет несколько JSX узлов вместе. +* [``](/reference/react/Fragment), или `<>...`, объединяет несколько JSX узлов. * [``](/reference/react/Profiler) измеряет производительность рендера компонентов. * [``](/reference/react/Suspense) отображает заглушку, пока загружаются дочерние компоненты. * [``](/reference/react/StrictMode) включает дополнительные проверки в режиме разработки, они помогают находить баги раньше. From d555f64773cae5337150b03b0d5cc346deea65ff Mon Sep 17 00:00:00 2001 From: Palidos <36964844+Palidos@users.noreply.github.com> Date: Mon, 24 Apr 2023 21:16:19 +0300 Subject: [PATCH 005/233] Add translation to "Installation" --- src/components/MDX/MDXComponents.tsx | 2 +- .../MDX/Sandpack/DownloadButton.tsx | 4 +- .../MDX/Sandpack/OpenInCodeSandboxButton.tsx | 4 +- src/components/MDX/Sandpack/ResetButton.tsx | 4 +- src/components/MDX/TerminalBlock.tsx | 2 +- src/content/learn/installation.md | 115 +++++++++--------- 6 files changed, 66 insertions(+), 65 deletions(-) diff --git a/src/components/MDX/MDXComponents.tsx b/src/components/MDX/MDXComponents.tsx index ba531c9f0..7fd5bbc35 100644 --- a/src/components/MDX/MDXComponents.tsx +++ b/src/components/MDX/MDXComponents.tsx @@ -173,7 +173,7 @@ function YouWillLearn({ children: any; isChapter?: boolean; }) { - let title = isChapter ? 'In this chapter' : 'You will learn'; + let title = isChapter ? 'В этой главе' : 'Вы узнаете'; return {children}; } diff --git a/src/components/MDX/Sandpack/DownloadButton.tsx b/src/components/MDX/Sandpack/DownloadButton.tsx index 4181dbe95..9de75177d 100644 --- a/src/components/MDX/Sandpack/DownloadButton.tsx +++ b/src/components/MDX/Sandpack/DownloadButton.tsx @@ -98,9 +98,9 @@ ${css} ); } diff --git a/src/components/MDX/Sandpack/OpenInCodeSandboxButton.tsx b/src/components/MDX/Sandpack/OpenInCodeSandboxButton.tsx index 42a2d2743..18047edb9 100644 --- a/src/components/MDX/Sandpack/OpenInCodeSandboxButton.tsx +++ b/src/components/MDX/Sandpack/OpenInCodeSandboxButton.tsx @@ -9,13 +9,13 @@ export const OpenInCodeSandboxButton = () => { return ( + title="Открыть в CodeSandbox"> - Fork + Форкнуть ); }; diff --git a/src/components/MDX/Sandpack/ResetButton.tsx b/src/components/MDX/Sandpack/ResetButton.tsx index 1ac413138..dbf9becf0 100644 --- a/src/components/MDX/Sandpack/ResetButton.tsx +++ b/src/components/MDX/Sandpack/ResetButton.tsx @@ -13,9 +13,9 @@ export function ResetButton({onReset}: ResetButtonProps) { ); } diff --git a/src/components/MDX/TerminalBlock.tsx b/src/components/MDX/TerminalBlock.tsx index 9fb5ff35f..3a692f5d4 100644 --- a/src/components/MDX/TerminalBlock.tsx +++ b/src/components/MDX/TerminalBlock.tsx @@ -65,7 +65,7 @@ function TerminalBlock({level = 'info', children}: TerminalBlockProps) { setCopied(true); }}> {' '} - {copied ? 'Copied' : 'Copy'} + {copied ? 'Скопировано' : 'Скопировать'} diff --git a/src/content/learn/installation.md b/src/content/learn/installation.md index c5426ea94..d4b83a085 100644 --- a/src/content/learn/installation.md +++ b/src/content/learn/installation.md @@ -1,57 +1,58 @@ ---- -title: Installation ---- - - - -React has been designed from the start for gradual adoption. You can use as little or as much React as you need. Whether you want to get a taste of React, add some interactivity to an HTML page, or start a complex React-powered app, this section will help you get started. - - - - - -* [How to start a new React project](/learn/start-a-new-react-project) -* [How to add React to an existing project](/learn/add-react-to-an-existing-project) -* [How to set up your editor](/learn/editor-setup) -* [How to install React Developer Tools](/learn/react-developer-tools) - - - -## Try React {/*try-react*/} - -You don't need to install anything to play with React. Try editing this sandbox! - - - -```js -function Greeting({ name }) { - return

Hello, {name}

; -} - -export default function App() { - return -} -``` - -
- -You can edit it directly or open it in a new tab by pressing the "Fork" button in the upper right corner. - -Most pages in the React documentation contain sandboxes like this. Outside of the React documentation, there are many online sandboxes that support React: for example, [CodeSandbox](https://codesandbox.io/s/new), [StackBlitz](https://stackblitz.com/fork/react), or [CodePen.](https://codepen.io/pen?&editors=0010&layout=left&prefill_data_id=3f4569d1-1b11-4bce-bd46-89090eed5ddb) - -### Try React locally {/*try-react-locally*/} - -To try React locally on your computer, [download this HTML page.](https://gist.githubusercontent.com/gaearon/0275b1e1518599bbeafcde4722e79ed1/raw/db72dcbf3384ee1708c4a07d3be79860db04bff0/example.html) Open it in your editor and in your browser! - -## Start a new React project {/*start-a-new-react-project*/} - -If you want to build an app or a website fully with React, [start a new React project.](/learn/start-a-new-react-project) - -## Add React to an existing project {/*add-react-to-an-existing-project*/} - -If want to try using React in your existing app or a website, [add React to an existing project.](/learn/add-react-to-an-existing-project) - -## Next steps {/*next-steps*/} - -Head to the [Quick Start](/learn) guide for a tour of the most important React concepts you will encounter every day. - +--- +title: Установка +--- + + + +React изначально был спроектирован так, чтобы его можно было внедрять постепенно. Другими словами, вы можете начать с малого и использовать только ту функциональность React, которая необходима вам в данный момент. Информация в этом разделе будет полезна в любой ситуации: при первом знакомстве с React, при создании простой динамической HTML-страницы и даже при проектировании сложного React-приложения. + + + + + + +* [Как создать новый React проект](/learn/start-a-new-react-project) +* [Как добавить React в уже существующий проект](/learn/add-react-to-an-existing-project) +* [Как настроить редактор кода](/learn/editor-setup) +* [Как установить React Developer Tools](/learn/react-developer-tools) + + + +## Пробуем React {/*try-react*/} + +Чтобы попробовать React даже устанавливать ничего не нужно. Редактируйте прямо в песочнице! + + + +```js +function Greeting({ name }) { + return

Hello, {name}

; +} + +export default function App() { + return +} +``` + +
+ +Вы можете редактировать прямо здесь или же открыть код в новой вкладке, нажав на кнопку "Форкнуть" в правом верхнем углу. + +Такие песочницы есть на большинстве страниц React документации. За пределами React документации тоже есть большое количество песочниц, поддерживающих React. Например: [CodeSandbox](https://codesandbox.io/s/new), [StackBlitz](https://stackblitz.com/fork/react) или [CodePen.](https://codepen.io/pen?&editors=0010&layout=left&prefill_data_id=3f4569d1-1b11-4bce-bd46-89090eed5ddb) + +### Поиграть с React локально {/*try-react-locally*/} + +Что бы поиграть с React локально на вашем компьютере, [скачайте эту HTML страницу.](https://gist.githubusercontent.com/gaearon/0275b1e1518599bbeafcde4722e79ed1/raw/db72dcbf3384ee1708c4a07d3be79860db04bff0/example.html) Откройте ее в своем текстовом редакторе и браузере! + +## Начать новый React проект {/*start-a-new-react-project*/} + +Если вы хотите создать приложение или сайт полностью на React — [создайте новый React проект.](/learn/start-a-new-react-project) + +## Добавить React в уже существующий проект {/*add-react-to-an-existing-project*/} + +Если вы хотите использовать React в уже существующем приложении или сайте — [добавьте React в уже существующий проект.](/learn/add-react-to-an-existing-project) + +## Дальнейшие шаги {/*next-steps*/} + +Перейдите к [Введению в React](/learn) для ознакомления с самыми важными его концепциями. + From 7dc884f183737fa2e6762cfcea32c7a6a6c6e10f Mon Sep 17 00:00:00 2001 From: Palidos <36964844+Palidos@users.noreply.github.com> Date: Mon, 24 Apr 2023 21:26:34 +0300 Subject: [PATCH 006/233] =?UTF-8?q?Fix=20=D1=81onjunction?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/content/learn/installation.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/content/learn/installation.md b/src/content/learn/installation.md index d4b83a085..ef8e56322 100644 --- a/src/content/learn/installation.md +++ b/src/content/learn/installation.md @@ -20,7 +20,7 @@ React изначально был спроектирован так, чтобы ## Пробуем React {/*try-react*/} -Чтобы попробовать React даже устанавливать ничего не нужно. Редактируйте прямо в песочнице! +Чтобы попробовать React, даже устанавливать ничего не нужно. Редактируйте прямо в песочнице! @@ -38,7 +38,7 @@ export default function App() { Вы можете редактировать прямо здесь или же открыть код в новой вкладке, нажав на кнопку "Форкнуть" в правом верхнем углу. -Такие песочницы есть на большинстве страниц React документации. За пределами React документации тоже есть большое количество песочниц, поддерживающих React. Например: [CodeSandbox](https://codesandbox.io/s/new), [StackBlitz](https://stackblitz.com/fork/react) или [CodePen.](https://codepen.io/pen?&editors=0010&layout=left&prefill_data_id=3f4569d1-1b11-4bce-bd46-89090eed5ddb) +Такие песочницы есть на большинстве страниц React документации. За пределами React документации также есть большое количество песочниц, поддерживающих React. Например: [CodeSandbox](https://codesandbox.io/s/new), [StackBlitz](https://stackblitz.com/fork/react) или [CodePen.](https://codepen.io/pen?&editors=0010&layout=left&prefill_data_id=3f4569d1-1b11-4bce-bd46-89090eed5ddb) ### Поиграть с React локально {/*try-react-locally*/} From eb53fbd968abe4d9a2edea36eeba01b21ea88db4 Mon Sep 17 00:00:00 2001 From: Pavel Zenov Date: Tue, 25 Apr 2023 08:55:14 +0300 Subject: [PATCH 007/233] Initial stuff for Quick Start in Russian --- src/content/learn/index.md | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/content/learn/index.md b/src/content/learn/index.md index b57655bc4..60e7b774f 100644 --- a/src/content/learn/index.md +++ b/src/content/learn/index.md @@ -4,36 +4,35 @@ title: Quick Start -Welcome to the React documentation! This page will give you an introduction to the 80% of React concepts that you will use on a daily basis. - +Добро пожаловать в документацию React! Эта страница послужит вам введением в 80% концептов React, которые вы будете использовать каждый день. -- How to create and nest components -- How to add markup and styles -- How to display data -- How to render conditions and lists -- How to respond to events and update the screen -- How to share data between components +- Как создавать и вкладывать компоненты +- Как добавлять разметку и стили +- Как отображать данные +- Как отрисовывать условия и списки +- Как реагировать на события и обновлять экран +- Как обмениваться данными между компонентами ## Creating and nesting components {/*components*/} -React apps are made out of *components*. A component is a piece of the UI (user interface) that has its own logic and appearance. A component can be as small as a button, or as large as an entire page. +Приложения на React собираются из *компонентов*. Компонент — это часть пользовательского интерфейса, у которой есть свои логика и внешность. Компоненты в размерах разнятся от мелких кнопок до больших цельных страниц. -React components are JavaScript functions that return markup: +Компоненты React — это Javascript-функции, которые возвращают разметку: ```js function MyButton() { return ( - + ); } ``` -Now that you've declared `MyButton`, you can nest it into another component: +Теперь, когда вы объявили `MyButton`, вы можете вложить его в другой компонент: ```js {5} export default function MyApp() { @@ -46,9 +45,9 @@ export default function MyApp() { } ``` -Notice that `` starts with a capital letter. That's how you know it's a React component. React component names must always start with a capital letter, while HTML tags must be lowercase. +Заметьте, что `` начинается с заглавной буквы. Это отличительная черта компонентов React. Названия компонентов в React должны всегда начинаться с заглавной буквы, а теги HTML — с маленькой. -Have a look at the result: +Посмотрите на результат: From e15ff7656d69aac299e7b69ca99e4014b5ee701d Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Tue, 25 Apr 2023 10:56:36 +0300 Subject: [PATCH 008/233] Update conditional-rendering.md --- src/content/learn/conditional-rendering.md | 279 ++++++++++----------- 1 file changed, 135 insertions(+), 144 deletions(-) diff --git a/src/content/learn/conditional-rendering.md b/src/content/learn/conditional-rendering.md index cbae68cec..6ed5fab89 100644 --- a/src/content/learn/conditional-rendering.md +++ b/src/content/learn/conditional-rendering.md @@ -1,24 +1,23 @@ --- -title: Conditional Rendering +title: Условный рендеринг --- - +Твоим компонентам нужно будет часто отображать различные вещи в зависимости от различных условий. В React ты можешь реденрить JSX в зависимости от его условий, используя JavaScript операторы. Такие, как `if`, `&&` и `? :` Your components will often need to display different things depending on different conditions. In React, you can conditionally render JSX using JavaScript syntax like `if` statements, `&&`, and `? :` operators. - + -* How to return different JSX depending on a condition -* How to conditionally include or exclude a piece of JSX -* Common conditional syntax shortcuts you’ll encounter in React codebases +* Как вернуть разный JSX, в зависимости от его условия +* Как условно включить или исключить фрагмент JSX +* Общий условный синтаксис, который ты встретишь в кодовой базе React. -## Conditionally returning JSX {/*conditionally-returning-jsx*/} - -Let’s say you have a `PackingList` component rendering several `Item`s, which can be marked as packed or not: +## Условно возвращаемый JSX {/*conditionally-returning-jsx*/} +Допустим, у тебя есть `PackingList` компонент, который рендерит несколько `Item`ов, которые могут быть обозначены, как упакованные или неуправкованные: @@ -30,19 +29,19 @@ function Item({ name, isPacked }) { export default function PackingList() { return (
-

Sally Ride's Packing List

+

Список вещей Салли Райд

@@ -51,10 +50,10 @@ export default function PackingList() { ```
+ +Заметь, что некоторые `Item` компоненты имеют свой `isPacked` проп, который `true` вместо `false`. Ты хочешь добавить галочку (✔) к упакованным вещам, если if `isPacked={true}`. -Notice that some of the `Item` components have their `isPacked` prop set to `true` instead of `false`. You want to add a checkmark (✔) to packed items if `isPacked={true}`. - -You can write this as an [`if`/`else` statement](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/if...else) like so: +Ты можешь писать это как [`if`/`else` условие](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Statements/if...) таким образом: ```js if (isPacked) { @@ -62,8 +61,7 @@ if (isPacked) { } return
  • {name}
  • ; ``` - -If the `isPacked` prop is `true`, this code **returns a different JSX tree.** With this change, some of the items get a checkmark at the end: +Если `isPacked` проп - это `true`, то этот код **вернёт другое JSX дерево.** Вместе с этим изменением, то некоторые вещи получат галочку в конце: @@ -78,19 +76,19 @@ function Item({ name, isPacked }) { export default function PackingList() { return (
    -

    Sally Ride's Packing List

    +

    Список вещей Салли Райд

    @@ -100,13 +98,13 @@ export default function PackingList() {
    -Try editing what gets returned in either case, and see how the result changes! +Попробуйте отредактировать то, что возвращается в обоих случаях, и посмотрите, как изменится результат! -Notice how you're creating branching logic with JavaScript's `if` and `return` statements. In React, control flow (like conditions) is handled by JavaScript. +Обратите внимание, как вы создаете разветвленную логику с помощью операторов JavaScript `if` и `return`. В React поток управления (как и условия) обрабатывается JavaScript. -### Conditionally returning nothing with `null` {/*conditionally-returning-nothing-with-null*/} +### Условно возвращаем ничего, с помощью `null` {/*conditionally-returning-nothing-with-null*/} -In some situations, you won't want to render anything at all. For example, say you don't want to show packed items at all. A component must return something. In this case, you can return `null`: +В некоторых ситуациях вы вообще не захотите ничего рендерить. Например, вы не хотите показывать упакованные предметы. Компонент должен что-то возвращать. В этом случае вы можете вернуть `null`: ```js if (isPacked) { @@ -114,8 +112,7 @@ if (isPacked) { } return
  • {name}
  • ; ``` - -If `isPacked` is true, the component will return nothing, `null`. Otherwise, it will return JSX to render. +Если `isPacked` true, то компонент не вернет ничего, `null`. В противном случае он вернет JSX для рендеринга. @@ -130,19 +127,19 @@ function Item({ name, isPacked }) { export default function PackingList() { return (
    -

    Sally Ride's Packing List

    +

    Список вещей Салли Райд

    @@ -151,24 +148,23 @@ export default function PackingList() { ```
    +На практике возврат `null` из компонента не является обычным делом, поскольку это может удивить разработчика, пытающегося его зарендерить. Чаще всего вы условно включаете или исключаете компонент JSX из родительского компонента. Вот как это сделать! -In practice, returning `null` from a component isn't common because it might surprise a developer trying to render it. More often, you would conditionally include or exclude the component in the parent component's JSX. Here's how to do that! - -## Conditionally including JSX {/*conditionally-including-jsx*/} +## Условное включение JSX {/*conditionally-including-jsx*/} -In the previous example, you controlled which (if any!) JSX tree would be returned by the component. You may already have noticed some duplication in the render output: +В предыдущем примере вы контролировали, какое JSX дерево будет возвращено компонентом (если вообще будет!). Возможно, вы уже заметили некоторое дублирование в выводе рендера: ```js
  • {name} ✔
  • ``` -is very similar to +очень похоже на ```js
  • {name}
  • ``` -Both of the conditional branches return `
  • ...
  • `: +Обе условные ветви возвращают `
  • ...
  • `: ```js if (isPacked) { @@ -176,14 +172,12 @@ if (isPacked) { } return
  • {name}
  • ; ``` +Хоть и такое дублирование не вредно, но оно может усложнить поддержание вашего кода. Что если вы захотите изменить `className`? Вам придется делать это в двух местах вашего кода! В такой ситуации вы можете условно включить небольшой JSX, чтобы сделать ваш код более [DRY.](https://ru.wikipedia.org/wiki/Don%E2%80%99t_repeat_yourself). -While this duplication isn't harmful, it could make your code harder to maintain. What if you want to change the `className`? You'd have to do it in two places in your code! In such a situation, you could conditionally include a little JSX to make your code more [DRY.](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself) +### Условный (тернанрый) оператор (`? :`) {/*conditional-ternary-operator--*/} -### Conditional (ternary) operator (`? :`) {/*conditional-ternary-operator--*/} - -JavaScript has a compact syntax for writing a conditional expression -- the [conditional operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator) or "ternary operator". - -Instead of this: +В JavaScript есть компактный синтаксис для записи условного выражения - [условный оператор](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Operators/Conditional_Operator) или "тернарный оператор". +Вместо этого: ```js if (isPacked) { @@ -192,7 +186,7 @@ if (isPacked) { return
  • {name}
  • ; ``` -You can write this: +Вы можете написать это: ```js return ( @@ -202,18 +196,16 @@ return ( ); ``` -You can read it as *"if `isPacked` is true, then (`?`) render `name + ' ✔'`, otherwise (`:`) render `name`"*. +Вы можете читать это как *"if `isPacked` это true, тогда (`?`) рендерим `name + ' ✔'`, в противном случае (`:`) рендерю `name`"*. -#### Are these two examples fully equivalent? {/*are-these-two-examples-fully-equivalent*/} - -If you're coming from an object-oriented programming background, you might assume that the two examples above are subtly different because one of them may create two different "instances" of `
  • `. But JSX elements aren't "instances" because they don't hold any internal state and aren't real DOM nodes. They're lightweight descriptions, like blueprints. So these two examples, in fact, *are* completely equivalent. [Preserving and Resetting State](/learn/preserving-and-resetting-state) goes into detail about how this works. +####Являются ли эти два примера полностью эквивалентными? {/*are-these-two-examples-fully-equivalent*/} +Если вы знакомы с объектно-ориентированным программированием, вы можете предположить, что два приведенных выше примера мало чем отличаются друг от друга, поскольку один из них может создавать два разных "экземпляра" `
  • `. Но элементы JSX не являются "экземплярами", потому что они не хранят никакого внутреннего состояния и не являются реальными узлами DOM. Это легкие описания, как чертежи. Так что эти два примера, на самом деле, *совершенно эквивалентны*. В [Сохранение и сброс состояния](/learn/preserving-and-resetting-state) подробно рассказывается о том, как это работает. -Now let's say you want to wrap the completed item's text into another HTML tag, like `` to strike it out. You can add even more newlines and parentheses so that it's easier to nest more JSX in each of the cases: - +Теперь предположим, что вы хотите обернуть текст завершенного элемента в другой HTML тег, например , чтобы вычеркнуть его. Вы можете добавить еще больше новых линий и круглых скобок, чтобы было проще вложить больше JSX в каждом из случаев: ```js @@ -234,19 +226,19 @@ function Item({ name, isPacked }) { export default function PackingList() { return (
    -

    Sally Ride's Packing List

    +

    Список вещей Салли Райд

    @@ -256,11 +248,10 @@ export default function PackingList() {
    -This style works well for simple conditions, but use it in moderation. If your components get messy with too much nested conditional markup, consider extracting child components to clean things up. In React, markup is a part of your code, so you can use tools like variables and functions to tidy up complex expressions. - -### Logical AND operator (`&&`) {/*logical-and-operator-*/} +Этот стиль хорошо работает для простых условий, но используйте его в меру. Если ваши компоненты становятся беспорядочными из-за слишком большого количества вложенной условной разметки, подумайте об извлечении дочерних компонентов, чтобы навести порядок. В React разметка является частью кода, поэтому вы можете использовать такие инструменты, как переменные и функции, чтобы привести в порядок сложные выражения. +### Логичксий И оператор (`&&`) {/*logical-and-operator-*/} -Another common shortcut you'll encounter is the [JavaScript logical AND (`&&`) operator.](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_AND#:~:text=The%20logical%20AND%20(%20%26%26%20)%20operator,it%20returns%20a%20Boolean%20value.) Inside React components, it often comes up when you want to render some JSX when the condition is true, **or render nothing otherwise.** With `&&`, you could conditionally render the checkmark only if `isPacked` is `true`: +Еще одно часто встречающееся сокращение [JavaScript логический И (`&&`) operator.](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Operators/Logical_AND) Внутри React компонентов, часто случается так, что тебе нужно зарендерить JSX, когда условие true, **или не рендерить ничего.** С `&&`, вы можете исходя из условия зарендерить галочку, if `isPacked` это `true`: ```js return ( @@ -270,9 +261,9 @@ return ( ); ``` -You can read this as *"if `isPacked`, then (`&&`) render the checkmark, otherwise, render nothing"*. +Вы можете читать это как *"if `isPacked`, тогда (`&&`) рендерим галочку, в противном случае, мы не рендерим ничего"*. -Here it is in action: +Вот это в действии: @@ -288,19 +279,19 @@ function Item({ name, isPacked }) { export default function PackingList() { return (
    -

    Sally Ride's Packing List

    +

    Список вещей Салли Райд

    @@ -310,30 +301,30 @@ export default function PackingList() {
    -A [JavaScript && expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_AND) returns the value of its right side (in our case, the checkmark) if the left side (our condition) is `true`. But if the condition is `false`, the whole expression becomes `false`. React considers `false` as a "hole" in the JSX tree, just like `null` or `undefined`, and doesn't render anything in its place. +A [JavaScript && выражение](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Operators/Logical_AND) возвращает значение его правой стороны (в нашем случае - это галочка) на левой стороне (наше условие) это `true`. Но если наше условие - `false`, тогда всё выражение становится `false`. React думает о `false` как о "дыре" внутри JSX дерева, прямо как о `null` или `undefined`, и React не рендерит ничего на этом месте. -**Don't put numbers on the left side of `&&`.** +**Не ставь числа по левую сторону `&&`.** -To test the condition, JavaScript converts the left side to a boolean automatically. However, if the left side is `0`, then the whole expression gets that value (`0`), and React will happily render `0` rather than nothing. +Чтобы проверить условие, JavaScript автоматически преобразует левую часть в булевое значение (true/false). Однако если левая часть равна `0`, то все выражение получает это значение (`0`), и React с радостью зарендерит `0`, а не ничего. -For example, a common mistake is to write code like `messageCount &&

    New messages

    `. It's easy to assume that it renders nothing when `messageCount` is `0`, but it really renders the `0` itself! +Например, распространенной ошибкой является написание кода типа `messageCount &&

    New messages

    `. Легко предположить, что он ничего не рендерит, когда `messageCount` равно `0`, но на самом деле он зарендерит `0`! -To fix it, make the left side a boolean: `messageCount > 0 &&

    New messages

    `. +Чтобы исправить это, сделайте левую часть булевым значением (true/false): `messageCount > 0 &&

    New messages

    `.
    -### Conditionally assigning JSX to a variable {/*conditionally-assigning-jsx-to-a-variable*/} +### Условное присвоение JSX к переменной {/*conditionally-assigning-jsx-to-a-variable*/} -When the shortcuts get in the way of writing plain code, try using an `if` statement and a variable. You can reassign variables defined with [`let`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let), so start by providing the default content you want to display, the name: +Когда сокращения встревают на пути к написанию понятного кода, то попробуйте использовать `if` оператор и переменную. Вы можете изменить переменные, написанные с помощью [`let`](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Statements/let), поэтому начните с предоставления содержимого по умолчанию, которое вы хотите отобразить, name: ```js let itemContent = name; ``` -Use an `if` statement to reassign a JSX expression to `itemContent` if `isPacked` is `true`: +Используй `if` оператор чтобы переназначить JSX выражение `itemContent` если `isPacked` это `true`: ```js if (isPacked) { @@ -341,7 +332,7 @@ if (isPacked) { } ``` -[Curly braces open the "window into JavaScript".](/learn/javascript-in-jsx-with-curly-braces#using-curly-braces-a-window-into-the-javascript-world) Embed the variable with curly braces in the returned JSX tree, nesting the previously calculated expression inside of JSX: +[Фигурные скобки открывают "окно в мир JavaScript".](/learn/javascript-in-jsx-with-curly-braces#using-curly-braces-a-window-into-the-javascript-world) Вставьте переменную с фигурными скобками в возвращаемое дерево JSX, вложив ранее вычисленное выражение внутрь JSX: ```js
  • @@ -349,7 +340,7 @@ if (isPacked) {
  • ``` -This style is the most verbose, but it's also the most flexible. Here it is in action: +Этот стиль самый многословный, но и самый гибкий. Вот он в действии: @@ -369,19 +360,19 @@ function Item({ name, isPacked }) { export default function PackingList() { return (
    -

    Sally Ride's Packing List

    +

    Список вещей Салли Райд

    @@ -391,7 +382,7 @@ export default function PackingList() {
    -Like before, this works not only for text, but for arbitrary JSX too: +Как и раньше, это работает не только для текста, но и для произвольного JSX: @@ -415,19 +406,19 @@ function Item({ name, isPacked }) { export default function PackingList() { return (
    -

    Sally Ride's Packing List

    +

    Список вещей Салли Райд

    @@ -437,16 +428,16 @@ export default function PackingList() {
    -If you're not familiar with JavaScript, this variety of styles might seem overwhelming at first. However, learning them will help you read and write any JavaScript code -- and not just React components! Pick the one you prefer for a start, and then consult this reference again if you forget how the other ones work. +Если вы не знакомы с JavaScript, то такое разнообразие стилей может показаться поначалу ошеломляющим. Однако их изучение поможет вам читать и писать любой код JavaScript - и не только компоненты React! Выберите для начала тот, который вам больше нравится, а затем снова обратитесь к этому справочнику, если вы забудете, как работают другие. -* In React, you control branching logic with JavaScript. -* You can return a JSX expression conditionally with an `if` statement. -* You can conditionally save some JSX to a variable and then include it inside other JSX by using the curly braces. -* In JSX, `{cond ? : }` means *"if `cond`, render ``, otherwise ``"*. -* In JSX, `{cond && }` means *"if `cond`, render ``, otherwise nothing"*. -* The shortcuts are common, but you don't have to use them if you prefer plain `if`. +* В React вы управляете логикой ветвления с помощью JavaScript. +* Вы можете возвращать выражение JSX условно с помощью оператора `if`. +* Вы можете условно сохранить логику JSX в переменную, а затем включить её в другие JSX с помощью фигурных скобок. +* В JSX, `{cond ? : }` означает *"if `cond`, рендери ``, в противном случае ``"*. +* В JSX, `{cond && }` означает *"if `cond`, рендери ``, иначе ничего"*. +* Эти сокращения являются общепринятыми, но вы не обязаны их использовать, если предпочитаете простые выражения. `if`. @@ -454,9 +445,9 @@ If you're not familiar with JavaScript, this variety of styles might seem overwh -#### Show an icon for incomplete items with `? :` {/*show-an-icon-for-incomplete-items-with--*/} +#### Покажи иконку для неупакованных вещей `? :` {/*show-an-icon-for-incomplete-items-with--*/} -Use the conditional operator (`cond ? a : b`) to render a ❌ if `isPacked` isn’t `true`. +Используй тернарный оператор (`cond ? a : b`) чтобы зарендерить ❌ if `isPacked` не равен `true`. @@ -472,19 +463,19 @@ function Item({ name, isPacked }) { export default function PackingList() { return (
    -

    Sally Ride's Packing List

    +

    Список вещей Салли Райд

    @@ -510,19 +501,19 @@ function Item({ name, isPacked }) { export default function PackingList() { return (
    -

    Sally Ride's Packing List

    +

    Список вещей Салли Райд

    @@ -534,15 +525,15 @@ export default function PackingList() { -#### Show the item importance with `&&` {/*show-the-item-importance-with-*/} +#### Покажи важность вещи с помощью `&&` {/*show-the-item-importance-with-*/} -In this example, each `Item` receives a numerical `importance` prop. Use the `&&` operator to render "_(Importance: X)_" in italics, but only for items that have non-zero importance. Your item list should end up looking like this: +В этом примере каждый `Item` получает числовой `importance` проп. Используй `&&` чтобы зарендерить "_(Важность: X)_" в italics стиле, но только для вещей важность которых больше 0. Твой конечный резульат должен выглядить вот так вот: -* Space suit _(Importance: 9)_ -* Helmet with a golden leaf -* Photo of Tam _(Importance: 6)_ +* Космический скафандр _(Важность: 9)_ +* Шлем с золотым листом +* Фотография Тэма _(Важность: 6)_ -Don't forget to add a space between the two labels! +Не забудьте добавить пробел между двумя метками! @@ -558,19 +549,19 @@ function Item({ name, importance }) { export default function PackingList() { return (
    -

    Sally Ride's Packing List

    +

    Список вещей Салли Райд

    @@ -582,7 +573,7 @@ export default function PackingList() { -This should do the trick: +Это должно сработать: @@ -593,7 +584,7 @@ function Item({ name, importance }) { {name} {importance > 0 && ' '} {importance > 0 && - (Importance: {importance}) + (Важность: {importance}) } ); @@ -602,19 +593,19 @@ function Item({ name, importance }) { export default function PackingList() { return (
    -

    Sally Ride's Packing List

    +

    Список вещей Салли Райд

    @@ -624,15 +615,15 @@ export default function PackingList() {
    -Note that you must write `importance > 0 && ...` rather than `importance && ...` so that if the `importance` is `0`, `0` isn't rendered as the result! +Помни, что ты должен писать `importance > 0 && ...` а не `importance && ...` поэтому если `importance` это `0`, то `0` не зарендерится как результат! -In this solution, two separate conditions are used to insert a space between then name and the importance label. Alternatively, you could use a fragment with a leading space: `importance > 0 && <> ...` or add a space immediately inside the ``: `importance > 0 && ...`. +В этом решении, два раздельных условия были использованы, чтобы вставить пробел между именем и меткой важности. В качестве альтернативы можно использовать фрагмент с ведущим пробелом: `importance > 0 && <> ...` или добавить пробел сразу внутри тега ``: `importance > 0 && ...`.
    -#### Refactor a series of `? :` to `if` and variables {/*refactor-a-series-of---to-if-and-variables*/} +#### Отрефактори тернарный оператор `? :` на `if` и переменными {/*refactor-a-series-of---to-if-and-variables*/} -This `Drink` component uses a series of `? :` conditions to show different information depending on whether the `name` prop is `"tea"` or `"coffee"`. The problem is that the information about each drink is spread across multiple conditions. Refactor this code to use a single `if` statement instead of three `? :` conditions. +Этот `Drink` компонент использует серию `? :` условий, чтобы показать разную информацию, которая зависит от `name` пропа, который `"tea"` или `"coffee"`. Проблема в том, что информация о каждом напитке распределена по нескольким условиям. Отрефактори этот код таким образом, чтобы использовать одно `if` условие вместо трёх `? :` условий. @@ -642,12 +633,12 @@ function Drink({ name }) {

    {name}

    -
    Part of plant
    +
    Часть растения
    {name === 'tea' ? 'leaf' : 'bean'}
    -
    Caffeine content
    -
    {name === 'tea' ? '15–70 mg/cup' : '80–185 mg/cup'}
    -
    Age
    -
    {name === 'tea' ? '4,000+ years' : '1,000+ years'}
    +
    Содержание кофеина
    +
    {name === 'tea' ? '15–70 мг/чашка' : '80–185 мг/чашка'}
    +
    Возраст
    +
    {name === 'tea' ? '4,000+ лет' : '1,000+ лет'}
    ); @@ -665,11 +656,11 @@ export default function DrinkList() {
    -Once you've refactored the code to use `if`, do you have further ideas on how to simplify it? + После рефакторинга кода с использованием `if` у вас есть идеи, как его упростить? -There are multiple ways you could go about this, but here is one starting point: + Есть несколько способов, но вот один из них, с которого можно начать: @@ -678,22 +669,22 @@ function Drink({ name }) { let part, caffeine, age; if (name === 'tea') { part = 'leaf'; - caffeine = '15–70 mg/cup'; - age = '4,000+ years'; + caffeine = '15–70 мг/чашка'; + age = '4,000+ лет'; } else if (name === 'coffee') { part = 'bean'; - caffeine = '80–185 mg/cup'; - age = '1,000+ years'; + caffeine = '80–185 мг/чашка'; + age = '1,000+ лет'; } return (

    {name}

    -
    Part of plant
    +
    Часть растения
    {part}
    -
    Caffeine content
    +
    Содержание кофеина
    {caffeine}
    -
    Age
    +
    Возраст
    {age}
    @@ -712,9 +703,9 @@ export default function DrinkList() {
    -Here the information about each drink is grouped together instead of being spread across multiple conditions. This makes it easier to add more drinks in the future. +Здесь информация о каждом напитке сгруппирована вместе, а не распределена по нескольким условиям. Это облегчает добавление новых напитков в будущем. -Another solution would be to remove the condition altogether by moving the information into objects: +Другим решением может быть полное удаление условий путем перемещения информации в объекты: @@ -722,13 +713,13 @@ Another solution would be to remove the condition altogether by moving the infor const drinks = { tea: { part: 'leaf', - caffeine: '15–70 mg/cup', - age: '4,000+ years' + caffeine: '15–70 мг/чашка', + age: '4,000+ лет' }, coffee: { part: 'bean', - caffeine: '80–185 mg/cup', - age: '1,000+ years' + caffeine: '80–185 мг/чашка', + age: '1,000+ лет' } }; @@ -738,11 +729,11 @@ function Drink({ name }) {

    {name}

    -
    Part of plant
    +
    Часть растения
    {info.part}
    -
    Caffeine content
    +
    Содержание кофеина
    {info.caffeine}
    -
    Age
    +
    Возраст
    {info.age}
    From bac5658737afe5db3fa0a3122bf866db7689042e Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Tue, 25 Apr 2023 10:59:43 +0300 Subject: [PATCH 009/233] Update conditional-rendering.md --- src/content/learn/conditional-rendering.md | 1 - 1 file changed, 1 deletion(-) diff --git a/src/content/learn/conditional-rendering.md b/src/content/learn/conditional-rendering.md index 6ed5fab89..7b3ece201 100644 --- a/src/content/learn/conditional-rendering.md +++ b/src/content/learn/conditional-rendering.md @@ -4,7 +4,6 @@ title: Условный рендеринг Твоим компонентам нужно будет часто отображать различные вещи в зависимости от различных условий. В React ты можешь реденрить JSX в зависимости от его условий, используя JavaScript операторы. Такие, как `if`, `&&` и `? :` -Your components will often need to display different things depending on different conditions. In React, you can conditionally render JSX using JavaScript syntax like `if` statements, `&&`, and `? :` operators. From 60b4bb895e52263a8a08c225655dcf3f3dbaaf06 Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Tue, 25 Apr 2023 11:00:53 +0300 Subject: [PATCH 010/233] Update conditional-rendering.md --- src/content/learn/conditional-rendering.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/conditional-rendering.md b/src/content/learn/conditional-rendering.md index 7b3ece201..8683e0b11 100644 --- a/src/content/learn/conditional-rendering.md +++ b/src/content/learn/conditional-rendering.md @@ -300,7 +300,7 @@ export default function PackingList() {
    -A [JavaScript && выражение](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Operators/Logical_AND) возвращает значение его правой стороны (в нашем случае - это галочка) на левой стороне (наше условие) это `true`. Но если наше условие - `false`, тогда всё выражение становится `false`. React думает о `false` как о "дыре" внутри JSX дерева, прямо как о `null` или `undefined`, и React не рендерит ничего на этом месте. +[JavaScript && выражение](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Operators/Logical_AND) возвращает значение его правой стороны (в нашем случае - это галочка) на левой стороне (наше условие) это `true`. Но если наше условие - `false`, тогда всё выражение становится `false`. React думает о `false` как о "дыре" внутри JSX дерева, прямо как о `null` или `undefined`, и React не рендерит ничего на этом месте. From f626d640457e5c3e557999d6e0dbf2cb22c55263 Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Tue, 25 Apr 2023 11:18:53 +0300 Subject: [PATCH 011/233] Update conditional-rendering.md --- src/content/learn/conditional-rendering.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/content/learn/conditional-rendering.md b/src/content/learn/conditional-rendering.md index 8683e0b11..f53146e38 100644 --- a/src/content/learn/conditional-rendering.md +++ b/src/content/learn/conditional-rendering.md @@ -3,6 +3,7 @@ title: Условный рендеринг --- + Твоим компонентам нужно будет часто отображать различные вещи в зависимости от различных условий. В React ты можешь реденрить JSX в зависимости от его условий, используя JavaScript операторы. Такие, как `if`, `&&` и `? :` @@ -16,6 +17,7 @@ title: Условный рендеринг
    ## Условно возвращаемый JSX {/*conditionally-returning-jsx*/} + Допустим, у тебя есть `PackingList` компонент, который рендерит несколько `Item`ов, которые могут быть обозначены, как упакованные или неуправкованные: @@ -60,6 +62,7 @@ if (isPacked) { } return
  • {name}
  • ; ``` + Если `isPacked` проп - это `true`, то этот код **вернёт другое JSX дерево.** Вместе с этим изменением, то некоторые вещи получат галочку в конце: @@ -111,6 +114,7 @@ if (isPacked) { } return
  • {name}
  • ; ``` + Если `isPacked` true, то компонент не вернет ничего, `null`. В противном случае он вернет JSX для рендеринга. @@ -147,6 +151,7 @@ export default function PackingList() { ``` + На практике возврат `null` из компонента не является обычным делом, поскольку это может удивить разработчика, пытающегося его зарендерить. Чаще всего вы условно включаете или исключаете компонент JSX из родительского компонента. Вот как это сделать! ## Условное включение JSX {/*conditionally-including-jsx*/} @@ -171,11 +176,13 @@ if (isPacked) { } return
  • {name}
  • ; ``` + Хоть и такое дублирование не вредно, но оно может усложнить поддержание вашего кода. Что если вы захотите изменить `className`? Вам придется делать это в двух местах вашего кода! В такой ситуации вы можете условно включить небольшой JSX, чтобы сделать ваш код более [DRY.](https://ru.wikipedia.org/wiki/Don%E2%80%99t_repeat_yourself). ### Условный (тернанрый) оператор (`? :`) {/*conditional-ternary-operator--*/} -В JavaScript есть компактный синтаксис для записи условного выражения - [условный оператор](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Operators/Conditional_Operator) или "тернарный оператор". +В JavaScript есть компактный синтаксис для написания условного выражения - [условный оператор](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Operators/Conditional_Operator) или "тернарный оператор". + Вместо этого: ```js @@ -202,9 +209,11 @@ return ( ####Являются ли эти два примера полностью эквивалентными? {/*are-these-two-examples-fully-equivalent*/} Если вы знакомы с объектно-ориентированным программированием, вы можете предположить, что два приведенных выше примера мало чем отличаются друг от друга, поскольку один из них может создавать два разных "экземпляра" `
  • `. Но элементы JSX не являются "экземплярами", потому что они не хранят никакого внутреннего состояния и не являются реальными узлами DOM. Это легкие описания, как чертежи. Так что эти два примера, на самом деле, *совершенно эквивалентны*. В [Сохранение и сброс состояния](/learn/preserving-and-resetting-state) подробно рассказывается о том, как это работает. + Теперь предположим, что вы хотите обернуть текст завершенного элемента в другой HTML тег, например , чтобы вычеркнуть его. Вы можете добавить еще больше новых линий и круглых скобок, чтобы было проще вложить больше JSX в каждом из случаев: + ```js @@ -248,6 +257,7 @@ export default function PackingList() { Этот стиль хорошо работает для простых условий, но используйте его в меру. Если ваши компоненты становятся беспорядочными из-за слишком большого количества вложенной условной разметки, подумайте об извлечении дочерних компонентов, чтобы навести порядок. В React разметка является частью кода, поэтому вы можете использовать такие инструменты, как переменные и функции, чтобы привести в порядок сложные выражения. + ### Логичксий И оператор (`&&`) {/*logical-and-operator-*/} Еще одно часто встречающееся сокращение [JavaScript логический И (`&&`) operator.](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Operators/Logical_AND) Внутри React компонентов, часто случается так, что тебе нужно зарендерить JSX, когда условие true, **или не рендерить ничего.** С `&&`, вы можете исходя из условия зарендерить галочку, if `isPacked` это `true`: From 730d0ed9cb332715d334ba1b110ff39052f06a74 Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Tue, 25 Apr 2023 11:21:19 +0300 Subject: [PATCH 012/233] Update conditional-rendering.md --- src/content/learn/conditional-rendering.md | 324 ++++++--------------- 1 file changed, 94 insertions(+), 230 deletions(-) diff --git a/src/content/learn/conditional-rendering.md b/src/content/learn/conditional-rendering.md index f53146e38..77d4cadcf 100644 --- a/src/content/learn/conditional-rendering.md +++ b/src/content/learn/conditional-rendering.md @@ -8,15 +8,15 @@ title: Условный рендеринг - + -* Как вернуть разный JSX, в зависимости от его условия -* Как условно включить или исключить фрагмент JSX -* Общий условный синтаксис, который ты встретишь в кодовой базе React. +- Как вернуть разный JSX, в зависимости от его условия +- Как условно включить или исключить фрагмент JSX +- Общий условный синтаксис, который ты встретишь в кодовой базе React. -## Условно возвращаемый JSX {/*conditionally-returning-jsx*/} +## Условно возвращаемый JSX {/_conditionally-returning-jsx_/} Допустим, у тебя есть `PackingList` компонент, который рендерит несколько `Item`ов, которые могут быть обозначены, как упакованные или неуправкованные: @@ -32,18 +32,9 @@ export default function PackingList() {

    Список вещей Салли Райд

      - - - + + +
    ); @@ -80,18 +71,9 @@ export default function PackingList() {

    Список вещей Салли Райд

      - - - + + +
    ); @@ -104,7 +86,7 @@ export default function PackingList() { Обратите внимание, как вы создаете разветвленную логику с помощью операторов JavaScript `if` и `return`. В React поток управления (как и условия) обрабатывается JavaScript. -### Условно возвращаем ничего, с помощью `null` {/*conditionally-returning-nothing-with-null*/} +### Условно возвращаем ничего, с помощью `null` {/_conditionally-returning-nothing-with-null_/} В некоторых ситуациях вы вообще не захотите ничего рендерить. Например, вы не хотите показывать упакованные предметы. Компонент должен что-то возвращать. В этом случае вы можете вернуть `null`: @@ -132,18 +114,9 @@ export default function PackingList() {

    Список вещей Салли Райд

      - - - + + +
    ); @@ -154,7 +127,7 @@ export default function PackingList() { На практике возврат `null` из компонента не является обычным делом, поскольку это может удивить разработчика, пытающегося его зарендерить. Чаще всего вы условно включаете или исключаете компонент JSX из родительского компонента. Вот как это сделать! -## Условное включение JSX {/*conditionally-including-jsx*/} +## Условное включение JSX {/_conditionally-including-jsx_/} В предыдущем примере вы контролировали, какое JSX дерево будет возвращено компонентом (если вообще будет!). Возможно, вы уже заметили некоторое дублирование в выводе рендера: @@ -179,7 +152,7 @@ return
  • {name}
  • ; Хоть и такое дублирование не вредно, но оно может усложнить поддержание вашего кода. Что если вы захотите изменить `className`? Вам придется делать это в двух местах вашего кода! В такой ситуации вы можете условно включить небольшой JSX, чтобы сделать ваш код более [DRY.](https://ru.wikipedia.org/wiki/Don%E2%80%99t_repeat_yourself). -### Условный (тернанрый) оператор (`? :`) {/*conditional-ternary-operator--*/} +### Условный (тернанрый) оператор (`? :`) {/_conditional-ternary-operator--_/} В JavaScript есть компактный синтаксис для написания условного выражения - [условный оператор](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Operators/Conditional_Operator) или "тернарный оператор". @@ -195,20 +168,16 @@ return
  • {name}
  • ; Вы можете написать это: ```js -return ( -
  • - {isPacked ? name + ' ✔' : name} -
  • -); +return
  • {isPacked ? name + " ✔" : name}
  • ; ``` -Вы можете читать это как *"if `isPacked` это true, тогда (`?`) рендерим `name + ' ✔'`, в противном случае (`:`) рендерю `name`"*. +Вы можете читать это как _"if `isPacked` это true, тогда (`?`) рендерим `name + ' ✔'`, в противном случае (`:`) рендерю `name`"_. -####Являются ли эти два примера полностью эквивалентными? {/*are-these-two-examples-fully-equivalent*/} +####Являются ли эти два примера полностью эквивалентными? {/_are-these-two-examples-fully-equivalent_/} -Если вы знакомы с объектно-ориентированным программированием, вы можете предположить, что два приведенных выше примера мало чем отличаются друг от друга, поскольку один из них может создавать два разных "экземпляра" `
  • `. Но элементы JSX не являются "экземплярами", потому что они не хранят никакого внутреннего состояния и не являются реальными узлами DOM. Это легкие описания, как чертежи. Так что эти два примера, на самом деле, *совершенно эквивалентны*. В [Сохранение и сброс состояния](/learn/preserving-and-resetting-state) подробно рассказывается о том, как это работает. +Если вы знакомы с объектно-ориентированным программированием, вы можете предположить, что два приведенных выше примера мало чем отличаются друг от друга, поскольку один из них может создавать два разных "экземпляра" `
  • `. Но элементы JSX не являются "экземплярами", потому что они не хранят никакого внутреннего состояния и не являются реальными узлами DOM. Это легкие описания, как чертежи. Так что эти два примера, на самом деле, _совершенно эквивалентны_. В [Сохранение и сброс состояния](/learn/preserving-and-resetting-state) подробно рассказывается о том, как это работает. @@ -218,17 +187,7 @@ return ( ```js function Item({ name, isPacked }) { - return ( -
  • - {isPacked ? ( - - {name + ' ✔'} - - ) : ( - name - )} -
  • - ); + return
  • {isPacked ? {name + " ✔"} : name}
  • ; } export default function PackingList() { @@ -236,18 +195,9 @@ export default function PackingList() {

    Список вещей Салли Райд

      - - - + + +
    ); @@ -258,19 +208,19 @@ export default function PackingList() { Этот стиль хорошо работает для простых условий, но используйте его в меру. Если ваши компоненты становятся беспорядочными из-за слишком большого количества вложенной условной разметки, подумайте об извлечении дочерних компонентов, чтобы навести порядок. В React разметка является частью кода, поэтому вы можете использовать такие инструменты, как переменные и функции, чтобы привести в порядок сложные выражения. -### Логичксий И оператор (`&&`) {/*logical-and-operator-*/} +### Логичксий И оператор (`&&`) {/_logical-and-operator-_/} -Еще одно часто встречающееся сокращение [JavaScript логический И (`&&`) operator.](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Operators/Logical_AND) Внутри React компонентов, часто случается так, что тебе нужно зарендерить JSX, когда условие true, **или не рендерить ничего.** С `&&`, вы можете исходя из условия зарендерить галочку, if `isPacked` это `true`: +Еще одно часто встречающееся сокращение [JavaScript логический И (`&&`) оператор.](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Operators/Logical_AND) Внутри React компонентов, часто случается так, что тебе нужно зарендерить JSX, когда условие true, **или не рендерить ничего.** С `&&`, вы можете исходя из условия зарендерить галочку, if `isPacked` это `true`: ```js return (
  • - {name} {isPacked && '✔'} + {name} {isPacked && "✔"}
  • ); ``` -Вы можете читать это как *"if `isPacked`, тогда (`&&`) рендерим галочку, в противном случае, мы не рендерим ничего"*. +Вы можете читать это как _"if `isPacked`, тогда (`&&`) рендерим галочку, в противном случае, мы не рендерим ничего"_. Вот это в действии: @@ -280,7 +230,7 @@ return ( function Item({ name, isPacked }) { return (
  • - {name} {isPacked && '✔'} + {name} {isPacked && "✔"}
  • ); } @@ -290,18 +240,9 @@ export default function PackingList() {

    Список вещей Салли Райд

      - - - + + +
    ); @@ -312,7 +253,6 @@ export default function PackingList() { [JavaScript && выражение](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Operators/Logical_AND) возвращает значение его правой стороны (в нашем случае - это галочка) на левой стороне (наше условие) это `true`. Но если наше условие - `false`, тогда всё выражение становится `false`. React думает о `false` как о "дыре" внутри JSX дерева, прямо как о `null` или `undefined`, и React не рендерит ничего на этом месте. - **Не ставь числа по левую сторону `&&`.** @@ -325,7 +265,7 @@ export default function PackingList() { -### Условное присвоение JSX к переменной {/*conditionally-assigning-jsx-to-a-variable*/} +### Условное присвоение JSX к переменной {/_conditionally-assigning-jsx-to-a-variable_/} Когда сокращения встревают на пути к написанию понятного кода, то попробуйте использовать `if` оператор и переменную. Вы можете изменить переменные, написанные с помощью [`let`](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Statements/let), поэтому начните с предоставления содержимого по умолчанию, которое вы хотите отобразить, name: @@ -344,9 +284,7 @@ if (isPacked) { [Фигурные скобки открывают "окно в мир JavaScript".](/learn/javascript-in-jsx-with-curly-braces#using-curly-braces-a-window-into-the-javascript-world) Вставьте переменную с фигурными скобками в возвращаемое дерево JSX, вложив ранее вычисленное выражение внутрь JSX: ```js -
  • - {itemContent} -
  • +
  • {itemContent}
  • ``` Этот стиль самый многословный, но и самый гибкий. Вот он в действии: @@ -359,11 +297,7 @@ function Item({ name, isPacked }) { if (isPacked) { itemContent = name + " ✔"; } - return ( -
  • - {itemContent} -
  • - ); + return
  • {itemContent}
  • ; } export default function PackingList() { @@ -371,18 +305,9 @@ export default function PackingList() {

    Список вещей Салли Райд

      - - - + + +
    ); @@ -399,17 +324,9 @@ export default function PackingList() { function Item({ name, isPacked }) { let itemContent = name; if (isPacked) { - itemContent = ( - - {name + " ✔"} - - ); + itemContent = {name + " ✔"}; } - return ( -
  • - {itemContent} -
  • - ); + return
  • {itemContent}
  • ; } export default function PackingList() { @@ -417,18 +334,9 @@ export default function PackingList() {

    Список вещей Салли Райд

      - - - + + +
    ); @@ -441,20 +349,18 @@ export default function PackingList() { -* В React вы управляете логикой ветвления с помощью JavaScript. -* Вы можете возвращать выражение JSX условно с помощью оператора `if`. -* Вы можете условно сохранить логику JSX в переменную, а затем включить её в другие JSX с помощью фигурных скобок. -* В JSX, `{cond ?
    : }` означает *"if `cond`, рендери ``, в противном случае ``"*. -* В JSX, `{cond && }` означает *"if `cond`, рендери ``, иначе ничего"*. -* Эти сокращения являются общепринятыми, но вы не обязаны их использовать, если предпочитаете простые выражения. `if`. +- В React вы управляете логикой ветвления с помощью JavaScript. +- Вы можете возвращать выражение JSX условно с помощью оператора `if`. +- Вы можете условно сохранить логику JSX в переменную, а затем включить её в другие JSX с помощью фигурных скобок. +- В JSX, `{cond ? : }` означает _"if `cond`, рендери ``, в противном случае ``"_. +- В JSX, `{cond && }` означает _"if `cond`, рендери ``, иначе ничего"_. +- Эти сокращения являются общепринятыми, но вы не обязаны их использовать, если предпочитаете простые выражения. `if`. - - -#### Покажи иконку для неупакованных вещей `? :` {/*show-an-icon-for-incomplete-items-with--*/} +#### Покажи иконку для неупакованных вещей `? :` {/_show-an-icon-for-incomplete-items-with--_/} Используй тернарный оператор (`cond ? a : b`) чтобы зарендерить ❌ if `isPacked` не равен `true`. @@ -464,7 +370,7 @@ export default function PackingList() { function Item({ name, isPacked }) { return (
  • - {name} {isPacked && '✔'} + {name} {isPacked && "✔"}
  • ); } @@ -474,18 +380,9 @@ export default function PackingList() {

    Список вещей Салли Райд

      - - - + + +
    ); @@ -502,7 +399,7 @@ export default function PackingList() { function Item({ name, isPacked }) { return (
  • - {name} {isPacked ? '✔' : '❌'} + {name} {isPacked ? "✔" : "❌"}
  • ); } @@ -512,18 +409,9 @@ export default function PackingList() {

    Список вещей Салли Райд

      - - - + + +
    ); @@ -534,13 +422,13 @@ export default function PackingList() { -#### Покажи важность вещи с помощью `&&` {/*show-the-item-importance-with-*/} +#### Покажи важность вещи с помощью `&&` {/_show-the-item-importance-with-_/} В этом примере каждый `Item` получает числовой `importance` проп. Используй `&&` чтобы зарендерить "_(Важность: X)_" в italics стиле, но только для вещей важность которых больше 0. Твой конечный резульат должен выглядить вот так вот: -* Космический скафандр _(Важность: 9)_ -* Шлем с золотым листом -* Фотография Тэма _(Важность: 6)_ +- Космический скафандр _(Важность: 9)_ +- Шлем с золотым листом +- Фотография Тэма _(Важность: 6)_ Не забудьте добавить пробел между двумя метками! @@ -548,11 +436,7 @@ export default function PackingList() { ```js function Item({ name, importance }) { - return ( -
  • - {name} -
  • - ); + return
  • {name}
  • ; } export default function PackingList() { @@ -560,18 +444,9 @@ export default function PackingList() {

    Список вещей Салли Райд

      - - - + + +
    ); @@ -591,10 +466,8 @@ function Item({ name, importance }) { return (
  • {name} - {importance > 0 && ' '} - {importance > 0 && - (Важность: {importance}) - } + {importance > 0 && " "} + {importance > 0 && (Важность: {importance})}
  • ); } @@ -604,18 +477,9 @@ export default function PackingList() {

    Список вещей Салли Райд

      - - - + + +
    ); @@ -626,11 +490,11 @@ export default function PackingList() { Помни, что ты должен писать `importance > 0 && ...` а не `importance && ...` поэтому если `importance` это `0`, то `0` не зарендерится как результат! -В этом решении, два раздельных условия были использованы, чтобы вставить пробел между именем и меткой важности. В качестве альтернативы можно использовать фрагмент с ведущим пробелом: `importance > 0 && <> ...` или добавить пробел сразу внутри тега ``: `importance > 0 && ...`. +В этом решении, два раздельных условия были использованы, чтобы вставить пробел между именем и меткой важности. В качестве альтернативы можно использовать фрагмент с ведущим пробелом: `importance > 0 && <> ...` или добавить пробел сразу внутри тега ``: `importance > 0 && ...`. -#### Отрефактори тернарный оператор `? :` на `if` и переменными {/*refactor-a-series-of---to-if-and-variables*/} +#### Отрефактори тернарный оператор `? :` на `if` и переменными {/_refactor-a-series-of---to-if-and-variables_/} Этот `Drink` компонент использует серию `? :` условий, чтобы показать разную информацию, которая зависит от `name` пропа, который `"tea"` или `"coffee"`. Проблема в том, что информация о каждом напитке распределена по нескольким условиям. Отрефактори этот код таким образом, чтобы использовать одно `if` условие вместо трёх `? :` условий. @@ -643,11 +507,11 @@ function Drink({ name }) {

    {name}

    Часть растения
    -
    {name === 'tea' ? 'leaf' : 'bean'}
    +
    {name === "tea" ? "leaf" : "bean"}
    Содержание кофеина
    -
    {name === 'tea' ? '15–70 мг/чашка' : '80–185 мг/чашка'}
    +
    {name === "tea" ? "15–70 мг/чашка" : "80–185 мг/чашка"}
    Возраст
    -
    {name === 'tea' ? '4,000+ лет' : '1,000+ лет'}
    +
    {name === "tea" ? "4,000+ лет" : "1,000+ лет"}
    ); @@ -665,25 +529,25 @@ export default function DrinkList() {
    - После рефакторинга кода с использованием `if` у вас есть идеи, как его упростить? +После рефакторинга кода с использованием `if` у вас есть идеи, как его упростить? - Есть несколько способов, но вот один из них, с которого можно начать: +Есть несколько способов, но вот один из них, с которого можно начать: ```js function Drink({ name }) { let part, caffeine, age; - if (name === 'tea') { - part = 'leaf'; - caffeine = '15–70 мг/чашка'; - age = '4,000+ лет'; - } else if (name === 'coffee') { - part = 'bean'; - caffeine = '80–185 мг/чашка'; - age = '1,000+ лет'; + if (name === "tea") { + part = "leaf"; + caffeine = "15–70 мг/чашка"; + age = "4,000+ лет"; + } else if (name === "coffee") { + part = "bean"; + caffeine = "80–185 мг/чашка"; + age = "1,000+ лет"; } return (
    @@ -721,15 +585,15 @@ export default function DrinkList() { ```js const drinks = { tea: { - part: 'leaf', - caffeine: '15–70 мг/чашка', - age: '4,000+ лет' + part: "leaf", + caffeine: "15–70 мг/чашка", + age: "4,000+ лет", }, coffee: { - part: 'bean', - caffeine: '80–185 мг/чашка', - age: '1,000+ лет' - } + part: "bean", + caffeine: "80–185 мг/чашка", + age: "1,000+ лет", + }, }; function Drink({ name }) { From 0bfb179b1e1ddecabe57dd54e4db126070fa0cbd Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Tue, 25 Apr 2023 11:22:32 +0300 Subject: [PATCH 013/233] Update conditional-rendering.md --- src/content/learn/conditional-rendering.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/conditional-rendering.md b/src/content/learn/conditional-rendering.md index 77d4cadcf..c6af2777f 100644 --- a/src/content/learn/conditional-rendering.md +++ b/src/content/learn/conditional-rendering.md @@ -251,7 +251,7 @@ export default function PackingList() { -[JavaScript && выражение](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Operators/Logical_AND) возвращает значение его правой стороны (в нашем случае - это галочка) на левой стороне (наше условие) это `true`. Но если наше условие - `false`, тогда всё выражение становится `false`. React думает о `false` как о "дыре" внутри JSX дерева, прямо как о `null` или `undefined`, и React не рендерит ничего на этом месте. +[JavaScript && выражение](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Operators/Logical_AND) возвращает значение его правой стороны (в нашем случае это галочка) на левой стороне (наше условие) это `true`. Но если наше условие - `false`, тогда всё выражение становится `false`. React думает о `false` как о "дыре" внутри JSX дерева, прямо как о `null` или `undefined`, и React не рендерит ничего на этом месте. From 4ced4b0c09853f5a05f3fa3ce1bc884dbce3ead1 Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Tue, 25 Apr 2023 11:32:37 +0300 Subject: [PATCH 014/233] Update conditional-rendering.md --- src/content/learn/conditional-rendering.md | 151 ++++++++++++++++----- 1 file changed, 120 insertions(+), 31 deletions(-) diff --git a/src/content/learn/conditional-rendering.md b/src/content/learn/conditional-rendering.md index c6af2777f..132dc8100 100644 --- a/src/content/learn/conditional-rendering.md +++ b/src/content/learn/conditional-rendering.md @@ -26,7 +26,6 @@ title: Условный рендеринг function Item({ name, isPacked }) { return
  • {name}
  • ; } - export default function PackingList() { return (
    @@ -71,9 +70,18 @@ export default function PackingList() {

    Список вещей Салли Райд

      - - - + + +
    ); @@ -114,9 +122,18 @@ export default function PackingList() {

    Список вещей Салли Райд

      - - - + + +
    ); @@ -195,9 +212,18 @@ export default function PackingList() {

    Список вещей Салли Райд

      - - - + + +
    ); @@ -240,9 +266,18 @@ export default function PackingList() {

    Список вещей Салли Райд

      - - - + + +
    ); @@ -305,9 +340,18 @@ export default function PackingList() {

    Список вещей Салли Райд

      - - - + + +
    ); @@ -334,9 +378,18 @@ export default function PackingList() {

    Список вещей Салли Райд

      - - - + + +
    ); @@ -380,9 +433,18 @@ export default function PackingList() {

    Список вещей Салли Райд

      - - - + + +
    ); @@ -409,9 +471,18 @@ export default function PackingList() {

    Список вещей Салли Райд

      - - - + + +
    ); @@ -444,9 +515,18 @@ export default function PackingList() {

    Список вещей Салли Райд

      - - - + + +
    ); @@ -477,9 +557,18 @@ export default function PackingList() {

    Список вещей Салли Райд

      - - - + + +
    ); From fc37a0519921fbe0e2fe1205e5322585adb2b27f Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Tue, 25 Apr 2023 11:36:18 +0300 Subject: [PATCH 015/233] Update conditional-rendering.md --- src/content/learn/conditional-rendering.md | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/content/learn/conditional-rendering.md b/src/content/learn/conditional-rendering.md index 132dc8100..b285db96e 100644 --- a/src/content/learn/conditional-rendering.md +++ b/src/content/learn/conditional-rendering.md @@ -31,9 +31,18 @@ export default function PackingList() {

    Список вещей Салли Райд

      - - - + + +
    ); From 7d55cc2386c53998f56bdcaa85809a3b075e9dca Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Tue, 25 Apr 2023 11:42:42 +0300 Subject: [PATCH 016/233] Update conditional-rendering.md --- src/content/learn/conditional-rendering.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/content/learn/conditional-rendering.md b/src/content/learn/conditional-rendering.md index b285db96e..c5b427e49 100644 --- a/src/content/learn/conditional-rendering.md +++ b/src/content/learn/conditional-rendering.md @@ -567,15 +567,15 @@ export default function PackingList() {

    Список вещей Салли Райд

    From 2b4f2fa10530e3881dfb6c29cb284ab81da542cd Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Tue, 25 Apr 2023 11:49:31 +0300 Subject: [PATCH 017/233] Update conditional-rendering.md --- src/content/learn/conditional-rendering.md | 44 ++++++++++++++++++---- 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/src/content/learn/conditional-rendering.md b/src/content/learn/conditional-rendering.md index c5b427e49..75e6cc42f 100644 --- a/src/content/learn/conditional-rendering.md +++ b/src/content/learn/conditional-rendering.md @@ -51,6 +51,7 @@ export default function PackingList() { + Заметь, что некоторые `Item` компоненты имеют свой `isPacked` проп, который `true` вместо `false`. Ты хочешь добавить галочку (✔) к упакованным вещам, если if `isPacked={true}`. Ты можешь писать это как [`if`/`else` условие](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Statements/if...) таким образом: @@ -194,7 +195,11 @@ return
  • {name}
  • ; Вы можете написать это: ```js -return
  • {isPacked ? name + " ✔" : name}
  • ; +return ( +
  • + {isPacked ? name + ' ✔' : name} +
  • +); ``` Вы можете читать это как _"if `isPacked` это true, тогда (`?`) рендерим `name + ' ✔'`, в противном случае (`:`) рендерю `name`"_. @@ -213,7 +218,17 @@ return
  • {isPacked ? name + " ✔" : name}
  • ; ```js function Item({ name, isPacked }) { - return
  • {isPacked ? {name + " ✔"} : name}
  • ; + return ( +
  • + {isPacked ? ( + + {name + ' ✔'} + + ) : ( + name + )} +
  • + ); } export default function PackingList() { @@ -327,9 +342,10 @@ if (isPacked) { [Фигурные скобки открывают "окно в мир JavaScript".](/learn/javascript-in-jsx-with-curly-braces#using-curly-braces-a-window-into-the-javascript-world) Вставьте переменную с фигурными скобками в возвращаемое дерево JSX, вложив ранее вычисленное выражение внутрь JSX: -```js -
  • {itemContent}
  • -``` + +
  • + {itemContent} +
  • Этот стиль самый многословный, но и самый гибкий. Вот он в действии: @@ -341,7 +357,11 @@ function Item({ name, isPacked }) { if (isPacked) { itemContent = name + " ✔"; } - return
  • {itemContent}
  • ; + return ( +
  • + {itemContent} +
  • + ); } export default function PackingList() { @@ -377,9 +397,17 @@ export default function PackingList() { function Item({ name, isPacked }) { let itemContent = name; if (isPacked) { - itemContent = {name + " ✔"}; + itemContent = ( + + {name + " ✔"} + + ); } - return
  • {itemContent}
  • ; + return ( +
  • + {itemContent} +
  • + ); } export default function PackingList() { From 6df1c9b7c2201d1eede1b82ac331934ed2c45aac Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Tue, 25 Apr 2023 11:52:11 +0300 Subject: [PATCH 018/233] Update conditional-rendering.md --- src/content/learn/conditional-rendering.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/content/learn/conditional-rendering.md b/src/content/learn/conditional-rendering.md index 75e6cc42f..40894a19e 100644 --- a/src/content/learn/conditional-rendering.md +++ b/src/content/learn/conditional-rendering.md @@ -311,8 +311,10 @@ export default function PackingList() { [JavaScript && выражение](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Operators/Logical_AND) возвращает значение его правой стороны (в нашем случае это галочка) на левой стороне (наше условие) это `true`. Но если наше условие - `false`, тогда всё выражение становится `false`. React думает о `false` как о "дыре" внутри JSX дерева, прямо как о `null` или `undefined`, и React не рендерит ничего на этом месте. + - + + **Не ставь числа по левую сторону `&&`.** @@ -342,10 +344,11 @@ if (isPacked) { [Фигурные скобки открывают "окно в мир JavaScript".](/learn/javascript-in-jsx-with-curly-braces#using-curly-braces-a-window-into-the-javascript-world) Вставьте переменную с фигурными скобками в возвращаемое дерево JSX, вложив ранее вычисленное выражение внутрь JSX: - +```js
  • {itemContent}
  • +``` Этот стиль самый многословный, но и самый гибкий. Вот он в действии: From de0aac4f8246aa4628ff84d1d2705e12e72908f3 Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Tue, 25 Apr 2023 11:55:57 +0300 Subject: [PATCH 019/233] Update conditional-rendering.md --- src/content/learn/conditional-rendering.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/content/learn/conditional-rendering.md b/src/content/learn/conditional-rendering.md index 40894a19e..5782b7022 100644 --- a/src/content/learn/conditional-rendering.md +++ b/src/content/learn/conditional-rendering.md @@ -311,10 +311,9 @@ export default function PackingList() { [JavaScript && выражение](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Operators/Logical_AND) возвращает значение его правой стороны (в нашем случае это галочка) на левой стороне (наше условие) это `true`. Но если наше условие - `false`, тогда всё выражение становится `false`. React думает о `false` как о "дыре" внутри JSX дерева, прямо как о `null` или `undefined`, и React не рендерит ничего на этом месте. - - + **Не ставь числа по левую сторону `&&`.** @@ -547,7 +546,11 @@ export default function PackingList() { ```js function Item({ name, importance }) { - return
  • {name}
  • ; + return ( +
  • + {name} +
  • + ); } export default function PackingList() { From 7791ddf2739d311297351ead9758f3113b6d203e Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Tue, 25 Apr 2023 11:58:45 +0300 Subject: [PATCH 020/233] Update conditional-rendering.md --- src/content/learn/conditional-rendering.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/content/learn/conditional-rendering.md b/src/content/learn/conditional-rendering.md index 5782b7022..266c286fe 100644 --- a/src/content/learn/conditional-rendering.md +++ b/src/content/learn/conditional-rendering.md @@ -589,8 +589,10 @@ function Item({ name, importance }) { return (
  • {name} - {importance > 0 && " "} - {importance > 0 && (Важность: {importance})} + {importance > 0 && ' '} + {importance > 0 && + (Importance: {importance}) + }
  • ); } From 895cb03f201e681bf79117d5a38e6c86fba69980 Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Tue, 25 Apr 2023 12:00:16 +0300 Subject: [PATCH 021/233] Update conditional-rendering.md --- src/content/learn/conditional-rendering.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/content/learn/conditional-rendering.md b/src/content/learn/conditional-rendering.md index 266c286fe..f49d28a29 100644 --- a/src/content/learn/conditional-rendering.md +++ b/src/content/learn/conditional-rendering.md @@ -450,6 +450,8 @@ export default function PackingList() { + + #### Покажи иконку для неупакованных вещей `? :` {/_show-an-icon-for-incomplete-items-with--_/} @@ -590,7 +592,7 @@ function Item({ name, importance }) {
  • {name} {importance > 0 && ' '} - {importance > 0 && + {importance > 0 && (Importance: {importance}) }
  • From 5d7e74b25074cd224eefdfee82d6d49fec81999c Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Tue, 25 Apr 2023 12:01:51 +0300 Subject: [PATCH 022/233] Update conditional-rendering.md --- src/content/learn/conditional-rendering.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/conditional-rendering.md b/src/content/learn/conditional-rendering.md index f49d28a29..00f56893e 100644 --- a/src/content/learn/conditional-rendering.md +++ b/src/content/learn/conditional-rendering.md @@ -450,7 +450,7 @@ export default function PackingList() { - + From cf7d8b80db5c2f639ad5ded3e7c978d4f29be6fc Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Tue, 25 Apr 2023 12:11:21 +0300 Subject: [PATCH 023/233] Update conditional-rendering.md --- src/content/learn/conditional-rendering.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/conditional-rendering.md b/src/content/learn/conditional-rendering.md index 00f56893e..64f53ac3a 100644 --- a/src/content/learn/conditional-rendering.md +++ b/src/content/learn/conditional-rendering.md @@ -310,7 +310,7 @@ export default function PackingList() { -[JavaScript && выражение](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Operators/Logical_AND) возвращает значение его правой стороны (в нашем случае это галочка) на левой стороне (наше условие) это `true`. Но если наше условие - `false`, тогда всё выражение становится `false`. React думает о `false` как о "дыре" внутри JSX дерева, прямо как о `null` или `undefined`, и React не рендерит ничего на этом месте. +[JavaScript && выражение](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Operators/Logical_AND) возвращает значение его правой стороны (в нашем случае это галочка) на левой стороне (наше условие) это `true`. Но если наше условие — `false`, тогда всё выражение становится `false`. React думает о `false` как о "дыре" внутри JSX дерева, прямо как о `null` или `undefined`, и React не рендерит ничего на этом месте. From 66f3addcb755745ce3bdc8c3baeb78f49763fc33 Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Tue, 25 Apr 2023 12:13:36 +0300 Subject: [PATCH 024/233] Update conditional-rendering.md --- src/content/learn/conditional-rendering.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/conditional-rendering.md b/src/content/learn/conditional-rendering.md index 64f53ac3a..5f5418b20 100644 --- a/src/content/learn/conditional-rendering.md +++ b/src/content/learn/conditional-rendering.md @@ -437,7 +437,7 @@ export default function PackingList() { -Если вы не знакомы с JavaScript, то такое разнообразие стилей может показаться поначалу ошеломляющим. Однако их изучение поможет вам читать и писать любой код JavaScript - и не только компоненты React! Выберите для начала тот, который вам больше нравится, а затем снова обратитесь к этому справочнику, если вы забудете, как работают другие. +Если вы не знакомы с JavaScript, то такое разнообразие стилей может показаться поначалу ошеломляющим. Однако их изучение поможет вам читать и писать любой код JavaScript — и не только компоненты React! Выберите для начала тот, который вам больше нравится, а затем снова обратитесь к этому справочнику, если вы забудете, как работают другие. From 00b30764f7287a5c6c4473e6badc09dad2d04719 Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Tue, 25 Apr 2023 12:26:07 +0300 Subject: [PATCH 025/233] Update conditional-rendering.md --- src/content/learn/conditional-rendering.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/content/learn/conditional-rendering.md b/src/content/learn/conditional-rendering.md index 5f5418b20..1618fb7fd 100644 --- a/src/content/learn/conditional-rendering.md +++ b/src/content/learn/conditional-rendering.md @@ -4,7 +4,7 @@ title: Условный рендеринг -Твоим компонентам нужно будет часто отображать различные вещи в зависимости от различных условий. В React ты можешь реденрить JSX в зависимости от его условий, используя JavaScript операторы. Такие, как `if`, `&&` и `? :` +Вашим компонентам нужно будет часто отображать различные вещи в зависимости от различных условий. В React вы можете реденрить JSX в зависимости от его условий, используя JavaScript операторы. Такие, как `if`, `&&` и `? :` @@ -12,13 +12,13 @@ title: Условный рендеринг - Как вернуть разный JSX, в зависимости от его условия - Как условно включить или исключить фрагмент JSX -- Общий условный синтаксис, который ты встретишь в кодовой базе React. +- Общий условный синтаксис, которые вы встретите в кодовой базе React. ## Условно возвращаемый JSX {/_conditionally-returning-jsx_/} -Допустим, у тебя есть `PackingList` компонент, который рендерит несколько `Item`ов, которые могут быть обозначены, как упакованные или неуправкованные: +Допустим, у вас есть `PackingList` компонент, который рендерит несколько `Item`ов, которые могут быть обозначены, как упакованные или неуправкованные: @@ -52,9 +52,9 @@ export default function PackingList() { -Заметь, что некоторые `Item` компоненты имеют свой `isPacked` проп, который `true` вместо `false`. Ты хочешь добавить галочку (✔) к упакованным вещам, если if `isPacked={true}`. +Заметь, что некоторые `Item` компоненты имеют свой `isPacked` проп, который `true` вместо `false`. Вы хотите добавить галочку (✔) к упакованным вещам, если if `isPacked={true}`. -Ты можешь писать это как [`if`/`else` условие](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Statements/if...) таким образом: +Вы можете писать это как [`if`/`else` условие](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Statements/if...) таким образом: ```js if (isPacked) { @@ -536,7 +536,7 @@ export default function PackingList() { #### Покажи важность вещи с помощью `&&` {/_show-the-item-importance-with-_/} -В этом примере каждый `Item` получает числовой `importance` проп. Используй `&&` чтобы зарендерить "_(Важность: X)_" в italics стиле, но только для вещей важность которых больше 0. Твой конечный резульат должен выглядить вот так вот: +В этом примере каждый `Item` получает числовой `importance` проп. Используй `&&` чтобы зарендерить "_(Важность: X)_" в italics стиле, но только для вещей важность которых больше 0. Ваш конечный резульат должен выглядеть вот так вот: - Космический скафандр _(Важность: 9)_ - Шлем с золотым листом From 49fcfe19014e4adc6826446f186129a6db3daf0c Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Tue, 25 Apr 2023 12:53:56 +0300 Subject: [PATCH 026/233] Update conditional-rendering.md --- src/content/learn/conditional-rendering.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/conditional-rendering.md b/src/content/learn/conditional-rendering.md index 1618fb7fd..4e2da7b65 100644 --- a/src/content/learn/conditional-rendering.md +++ b/src/content/learn/conditional-rendering.md @@ -63,7 +63,7 @@ if (isPacked) { return
  • {name}
  • ; ``` -Если `isPacked` проп - это `true`, то этот код **вернёт другое JSX дерево.** Вместе с этим изменением, то некоторые вещи получат галочку в конце: +Если `isPacked` проп - это `true`, то этот код **вернёт другое JSX дерево.** Вместе с этим изменением, некоторые вещи получат галочку в конце: From 64884e908378e3b27d0f744b9826385d717284db Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Tue, 25 Apr 2023 12:57:24 +0300 Subject: [PATCH 027/233] Update conditional-rendering.md --- src/content/learn/conditional-rendering.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/conditional-rendering.md b/src/content/learn/conditional-rendering.md index 4e2da7b65..6116d9e74 100644 --- a/src/content/learn/conditional-rendering.md +++ b/src/content/learn/conditional-rendering.md @@ -4,7 +4,7 @@ title: Условный рендеринг -Вашим компонентам нужно будет часто отображать различные вещи в зависимости от различных условий. В React вы можете реденрить JSX в зависимости от его условий, используя JavaScript операторы. Такие, как `if`, `&&` и `? :` +Вашим компонентам нужно часто отображать различные вещи в зависимости от различных условий. В React вы можете реденрить JSX в зависимости от его условий, используя JavaScript операторы. Такие, как `if`, `&&` и `? :` From d7aa356876e6e3a318406df62964a07dfbaaf3ff Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Tue, 25 Apr 2023 13:00:05 +0300 Subject: [PATCH 028/233] Update conditional-rendering.md --- src/content/learn/conditional-rendering.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/content/learn/conditional-rendering.md b/src/content/learn/conditional-rendering.md index 6116d9e74..12aecd279 100644 --- a/src/content/learn/conditional-rendering.md +++ b/src/content/learn/conditional-rendering.md @@ -63,7 +63,7 @@ if (isPacked) { return
  • {name}
  • ; ``` -Если `isPacked` проп - это `true`, то этот код **вернёт другое JSX дерево.** Вместе с этим изменением, некоторые вещи получат галочку в конце: +Если `isPacked` проп — это `true`, то этот код **вернёт другое JSX дерево.** Вместе с этим изменением, некоторые вещи получат галочку в конце: @@ -181,7 +181,7 @@ return
  • {name}
  • ; ### Условный (тернанрый) оператор (`? :`) {/_conditional-ternary-operator--_/} -В JavaScript есть компактный синтаксис для написания условного выражения - [условный оператор](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Operators/Conditional_Operator) или "тернарный оператор". +В JavaScript есть компактный синтаксис для написания условного выражения — [условный оператор](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Operators/Conditional_Operator) или "тернарный оператор". Вместо этого: From 8674f2af39d5f6f51005a921329a2d0b85f88978 Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Tue, 25 Apr 2023 13:05:47 +0300 Subject: [PATCH 029/233] Update conditional-rendering.md --- src/content/learn/conditional-rendering.md | 30 +++++++++++----------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/content/learn/conditional-rendering.md b/src/content/learn/conditional-rendering.md index 12aecd279..6697a3c7f 100644 --- a/src/content/learn/conditional-rendering.md +++ b/src/content/learn/conditional-rendering.md @@ -16,7 +16,7 @@ title: Условный рендеринг -## Условно возвращаемый JSX {/_conditionally-returning-jsx_/} +## Условно возвращаемый JSX {/*conditionally-returning-jsx*/} Допустим, у вас есть `PackingList` компонент, который рендерит несколько `Item`ов, которые могут быть обозначены, как упакованные или неуправкованные: @@ -104,7 +104,7 @@ export default function PackingList() { Обратите внимание, как вы создаете разветвленную логику с помощью операторов JavaScript `if` и `return`. В React поток управления (как и условия) обрабатывается JavaScript. -### Условно возвращаем ничего, с помощью `null` {/_conditionally-returning-nothing-with-null_/} +### Условно возвращаем ничего, с помощью `null` {/*conditionally-returning-nothing-with-null*/} В некоторых ситуациях вы вообще не захотите ничего рендерить. Например, вы не хотите показывать упакованные предметы. Компонент должен что-то возвращать. В этом случае вы можете вернуть `null`: @@ -154,7 +154,7 @@ export default function PackingList() { На практике возврат `null` из компонента не является обычным делом, поскольку это может удивить разработчика, пытающегося его зарендерить. Чаще всего вы условно включаете или исключаете компонент JSX из родительского компонента. Вот как это сделать! -## Условное включение JSX {/_conditionally-including-jsx_/} +## Условное включение JSX {/*conditionally-including-jsx*/} В предыдущем примере вы контролировали, какое JSX дерево будет возвращено компонентом (если вообще будет!). Возможно, вы уже заметили некоторое дублирование в выводе рендера: @@ -179,7 +179,7 @@ return
  • {name}
  • ; Хоть и такое дублирование не вредно, но оно может усложнить поддержание вашего кода. Что если вы захотите изменить `className`? Вам придется делать это в двух местах вашего кода! В такой ситуации вы можете условно включить небольшой JSX, чтобы сделать ваш код более [DRY.](https://ru.wikipedia.org/wiki/Don%E2%80%99t_repeat_yourself). -### Условный (тернанрый) оператор (`? :`) {/_conditional-ternary-operator--_/} +### Условный (тернанрый) оператор (`? :`) {/*conditional-ternary-operator--*/} В JavaScript есть компактный синтаксис для написания условного выражения — [условный оператор](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Operators/Conditional_Operator) или "тернарный оператор". @@ -202,13 +202,13 @@ return ( ); ``` -Вы можете читать это как _"if `isPacked` это true, тогда (`?`) рендерим `name + ' ✔'`, в противном случае (`:`) рендерю `name`"_. +Вы можете читать это как *"if `isPacked` это true, тогда (`?`) рендерим `name + ' ✔'`, в противном случае (`:`) рендерю `name`"*. -####Являются ли эти два примера полностью эквивалентными? {/_are-these-two-examples-fully-equivalent_/} +####Являются ли эти два примера полностью эквивалентными? {/*are-these-two-examples-fully-equivalent*/} -Если вы знакомы с объектно-ориентированным программированием, вы можете предположить, что два приведенных выше примера мало чем отличаются друг от друга, поскольку один из них может создавать два разных "экземпляра" `
  • `. Но элементы JSX не являются "экземплярами", потому что они не хранят никакого внутреннего состояния и не являются реальными узлами DOM. Это легкие описания, как чертежи. Так что эти два примера, на самом деле, _совершенно эквивалентны_. В [Сохранение и сброс состояния](/learn/preserving-and-resetting-state) подробно рассказывается о том, как это работает. +Если вы знакомы с объектно-ориентированным программированием, вы можете предположить, что два приведенных выше примера мало чем отличаются друг от друга, поскольку один из них может создавать два разных "экземпляра" `
  • `. Но элементы JSX не являются "экземплярами", потому что они не хранят никакого внутреннего состояния и не являются реальными узлами DOM. Это легкие описания, как чертежи. Так что эти два примера, на самом деле, *совершенно эквивалентны*. В [Сохранение и сброс состояния](/learn/preserving-and-resetting-state) подробно рассказывается о том, как это работает. @@ -258,7 +258,7 @@ export default function PackingList() { Этот стиль хорошо работает для простых условий, но используйте его в меру. Если ваши компоненты становятся беспорядочными из-за слишком большого количества вложенной условной разметки, подумайте об извлечении дочерних компонентов, чтобы навести порядок. В React разметка является частью кода, поэтому вы можете использовать такие инструменты, как переменные и функции, чтобы привести в порядок сложные выражения. -### Логичксий И оператор (`&&`) {/_logical-and-operator-_/} +### Логичксий И оператор (`&&`) {/*logical-and-operator-*/} Еще одно часто встречающееся сокращение [JavaScript логический И (`&&`) оператор.](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Operators/Logical_AND) Внутри React компонентов, часто случается так, что тебе нужно зарендерить JSX, когда условие true, **или не рендерить ничего.** С `&&`, вы можете исходя из условия зарендерить галочку, if `isPacked` это `true`: @@ -270,7 +270,7 @@ return ( ); ``` -Вы можете читать это как _"if `isPacked`, тогда (`&&`) рендерим галочку, в противном случае, мы не рендерим ничего"_. +Вы можете читать это как *"if `isPacked`, тогда (`&&`) рендерим галочку, в противном случае, мы не рендерим ничего"*. Вот это в действии: @@ -325,7 +325,7 @@ export default function PackingList() { -### Условное присвоение JSX к переменной {/_conditionally-assigning-jsx-to-a-variable_/} +### Условное присвоение JSX к переменной {/*conditionally-assigning-jsx-to-a-variable*/} Когда сокращения встревают на пути к написанию понятного кода, то попробуйте использовать `if` оператор и переменную. Вы можете изменить переменные, написанные с помощью [`let`](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Statements/let), поэтому начните с предоставления содержимого по умолчанию, которое вы хотите отобразить, name: @@ -444,8 +444,8 @@ export default function PackingList() { - В React вы управляете логикой ветвления с помощью JavaScript. - Вы можете возвращать выражение JSX условно с помощью оператора `if`. - Вы можете условно сохранить логику JSX в переменную, а затем включить её в другие JSX с помощью фигурных скобок. -- В JSX, `{cond ? : }` означает _"if `cond`, рендери ``, в противном случае ``"_. -- В JSX, `{cond && }` означает _"if `cond`, рендери ``, иначе ничего"_. +- В JSX, `{cond ? : }` означает *"if `cond`, рендери ``, в противном случае ``"*. +- В JSX, `{cond && }` означает *"if `cond`, рендери ``, иначе ничего"*. - Эти сокращения являются общепринятыми, но вы не обязаны их использовать, если предпочитаете простые выражения. `if`. @@ -454,7 +454,7 @@ export default function PackingList() { -#### Покажи иконку для неупакованных вещей `? :` {/_show-an-icon-for-incomplete-items-with--_/} +#### Покажи иконку для неупакованных вещей `? :` {/*show-an-icon-for-incomplete-items-with--*/} Используй тернарный оператор (`cond ? a : b`) чтобы зарендерить ❌ if `isPacked` не равен `true`. @@ -534,7 +534,7 @@ export default function PackingList() { -#### Покажи важность вещи с помощью `&&` {/_show-the-item-importance-with-_/} +#### Покажи важность вещи с помощью `&&` {/*show-the-item-importance-with-*/} В этом примере каждый `Item` получает числовой `importance` проп. Используй `&&` чтобы зарендерить "_(Важность: X)_" в italics стиле, но только для вещей важность которых больше 0. Ваш конечный резульат должен выглядеть вот так вот: @@ -630,7 +630,7 @@ export default function PackingList() { -#### Отрефактори тернарный оператор `? :` на `if` и переменными {/_refactor-a-series-of---to-if-and-variables_/} +#### Отрефактори тернарный оператор `? :` на `if` и переменными {/*refactor-a-series-of---to-if-and-variables*/} Этот `Drink` компонент использует серию `? :` условий, чтобы показать разную информацию, которая зависит от `name` пропа, который `"tea"` или `"coffee"`. Проблема в том, что информация о каждом напитке распределена по нескольким условиям. Отрефактори этот код таким образом, чтобы использовать одно `if` условие вместо трёх `? :` условий. From 522032947825f8dad1541acdd454c7fa6ef41d45 Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Tue, 25 Apr 2023 13:55:20 +0300 Subject: [PATCH 030/233] Update conditional-rendering.md --- src/content/learn/conditional-rendering.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/conditional-rendering.md b/src/content/learn/conditional-rendering.md index 6697a3c7f..6cd656320 100644 --- a/src/content/learn/conditional-rendering.md +++ b/src/content/learn/conditional-rendering.md @@ -212,7 +212,7 @@ return ( -Теперь предположим, что вы хотите обернуть текст завершенного элемента в другой HTML тег, например , чтобы вычеркнуть его. Вы можете добавить еще больше новых линий и круглых скобок, чтобы было проще вложить больше JSX в каждом из случаев: +Теперь предположим, что вы хотите обернуть текст завершенного элемента в другой HTML тег, например ``, чтобы вычеркнуть его. Вы можете добавить еще больше новых линий и круглых скобок, чтобы было проще вложить больше JSX в каждом из случаев: From abccea351c18f3964fc8469d47278e9a91f298c5 Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Tue, 25 Apr 2023 14:09:59 +0300 Subject: [PATCH 031/233] Update conditional-rendering.md --- src/content/learn/conditional-rendering.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/conditional-rendering.md b/src/content/learn/conditional-rendering.md index 6cd656320..507087307 100644 --- a/src/content/learn/conditional-rendering.md +++ b/src/content/learn/conditional-rendering.md @@ -206,7 +206,7 @@ return ( -####Являются ли эти два примера полностью эквивалентными? {/*are-these-two-examples-fully-equivalent*/} +#### Являются ли эти два примера полностью эквивалентными? {/*are-these-two-examples-fully-equivalent*/} Если вы знакомы с объектно-ориентированным программированием, вы можете предположить, что два приведенных выше примера мало чем отличаются друг от друга, поскольку один из них может создавать два разных "экземпляра" `
  • `. Но элементы JSX не являются "экземплярами", потому что они не хранят никакого внутреннего состояния и не являются реальными узлами DOM. Это легкие описания, как чертежи. Так что эти два примера, на самом деле, *совершенно эквивалентны*. В [Сохранение и сброс состояния](/learn/preserving-and-resetting-state) подробно рассказывается о том, как это работает. From 6d0fa5223f86f1cf0e795f0b37a922f33f7ff590 Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Tue, 25 Apr 2023 14:33:10 +0300 Subject: [PATCH 032/233] Update conditional-rendering.md --- src/content/learn/conditional-rendering.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/content/learn/conditional-rendering.md b/src/content/learn/conditional-rendering.md index 507087307..f871b570b 100644 --- a/src/content/learn/conditional-rendering.md +++ b/src/content/learn/conditional-rendering.md @@ -12,13 +12,13 @@ title: Условный рендеринг - Как вернуть разный JSX, в зависимости от его условия - Как условно включить или исключить фрагмент JSX -- Общий условный синтаксис, которые вы встретите в кодовой базе React. +- Общий условный синтаксис, который вы встретите в кодовой базе React. ## Условно возвращаемый JSX {/*conditionally-returning-jsx*/} -Допустим, у вас есть `PackingList` компонент, который рендерит несколько `Item`ов, которые могут быть обозначены, как упакованные или неуправкованные: +Допустим, у вас есть `PackingList` компонент, который рендерит несколько `Item`, которые могут быть обозначены, как упакованные или неуправкованные: @@ -333,7 +333,7 @@ export default function PackingList() { let itemContent = name; ``` -Используй `if` оператор чтобы переназначить JSX выражение `itemContent` если `isPacked` это `true`: +Используйте `if` оператор чтобы переназначить JSX выражение `itemContent` если `isPacked` это `true`: ```js if (isPacked) { @@ -454,7 +454,7 @@ export default function PackingList() { -#### Покажи иконку для неупакованных вещей `? :` {/*show-an-icon-for-incomplete-items-with--*/} +#### Покажи иконку для неупакованных вещей с `? :` {/*show-an-icon-for-incomplete-items-with--*/} Используй тернарный оператор (`cond ? a : b`) чтобы зарендерить ❌ if `isPacked` не равен `true`. @@ -593,7 +593,7 @@ function Item({ name, importance }) { {name} {importance > 0 && ' '} {importance > 0 && - (Importance: {importance}) + (Важность: {importance}) }
  • ); @@ -630,9 +630,9 @@ export default function PackingList() { -#### Отрефактори тернарный оператор `? :` на `if` и переменными {/*refactor-a-series-of---to-if-and-variables*/} +#### Отрефактори тернарный оператор `? :` на `if` с переменной {/*refactor-a-series-of---to-if-and-variables*/} -Этот `Drink` компонент использует серию `? :` условий, чтобы показать разную информацию, которая зависит от `name` пропа, который `"tea"` или `"coffee"`. Проблема в том, что информация о каждом напитке распределена по нескольким условиям. Отрефактори этот код таким образом, чтобы использовать одно `if` условие вместо трёх `? :` условий. +Этот `Drink` компонент использует серию `? :` условий, чтобы показать разную информацию, которая зависит от `name` пропа, который `"tea"` или `"coffee"`. Проблема в том, что информация о каждом напитке распределена по нескольким условиям. Отрефактори этот код так, чтобы использовать одно `if` условие вместо трёх `? :` условий. From a8c91f7874c06cab1453080c58761c9d16c74cda Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Tue, 25 Apr 2023 16:46:36 +0300 Subject: [PATCH 033/233] Update conditional-rendering.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit лишняя буква --- src/content/learn/conditional-rendering.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/conditional-rendering.md b/src/content/learn/conditional-rendering.md index f871b570b..628c7b70f 100644 --- a/src/content/learn/conditional-rendering.md +++ b/src/content/learn/conditional-rendering.md @@ -18,7 +18,7 @@ title: Условный рендеринг ## Условно возвращаемый JSX {/*conditionally-returning-jsx*/} -Допустим, у вас есть `PackingList` компонент, который рендерит несколько `Item`, которые могут быть обозначены, как упакованные или неуправкованные: +Допустим, у вас есть `PackingList` компонент, который рендерит несколько `Item`, которые могут быть обозначены, как упакованные или неупавкованные: From 4118bfe502ea32ce98eaa51d08558017e120f29b Mon Sep 17 00:00:00 2001 From: Pavel Zenov Date: Tue, 25 Apr 2023 21:39:54 +0300 Subject: [PATCH 034/233] Almost all text's ready --- src/content/learn/index.md | 160 ++++++++++++++++++------------------- 1 file changed, 80 insertions(+), 80 deletions(-) diff --git a/src/content/learn/index.md b/src/content/learn/index.md index 60e7b774f..08aa2b57c 100644 --- a/src/content/learn/index.md +++ b/src/content/learn/index.md @@ -38,7 +38,7 @@ function MyButton() { export default function MyApp() { return (
    -

    Welcome to my app

    +

    Добро пожаловать в моё приложение

    ); @@ -55,7 +55,7 @@ export default function MyApp() { function MyButton() { return ( ); } @@ -63,7 +63,7 @@ function MyButton() { export default function MyApp() { return (
    -

    Welcome to my app

    +

    Добро пожаловать в моё приложение

    ); @@ -72,49 +72,49 @@ export default function MyApp() {
    -The `export default` keywords specify the main component in the file. If you're not familiar with some piece of JavaScript syntax, [MDN](https://developer.mozilla.org/en-US/docs/web/javascript/reference/statements/export) and [javascript.info](https://javascript.info/import-export) have great references. +Ключевые слова `export default` указывают на основной компонент в файле. Если вам не знакомы некоторые аспекты синтаксиса JavaScript, [MDN](https://developer.mozilla.org/ru-RU/docs/web/javascript/reference/statements/export) и [learn.javascript.ru](https://learn.javascript.ru/import-export) послужат для вас хорошими справочниками. -## Writing markup with JSX {/*writing-markup-with-jsx*/} +## Пишем разметку с JSX {/*writing-markup-with-jsx*/} -The markup syntax you've seen above is called *JSX*. It is optional, but most React projects use JSX for its convenience. All of the [tools we recommend for local development](/learn/installation) support JSX out of the box. +Используемый в примерах выше синтаксис разметки называется *JSX*. Его необязательно использовать, но большинство проектов на React используют JSX в силу его удобства. Все [инструменты, которые мы рекомендуем для локальной разработки,](/learn/installation) поддерживают JSX из коробки. -JSX is stricter than HTML. You have to close tags like `
    `. Your component also can't return multiple JSX tags. You have to wrap them into a shared parent, like a `
    ...
    ` or an empty `<>...` wrapper: +JSX строже HTML. Вам нужно закрывать теги вроде `
    `. Ваш компонент также не может возвращать несколько JSX-тегов. Их нужно будет обернуть внутрь общего родителя, например, `
    ...
    ` или пустую обёртку вида `<>...`: ```js {3,6} function AboutPage() { return ( <> -

    About

    -

    Hello there.
    How do you do?

    +

    Обо мне

    +

    Привет.
    Как дела?

    ); } ``` -If you have a lot of HTML to port to JSX, you can use an [online converter.](https://transform.tools/html-to-jsx) +Если вам нужно перевести большое количество HTML-верстки в JSX, вы можете использовать [онлайн-конвертер.](https://transform.tools/html-to-jsx) -## Adding styles {/*adding-styles*/} +## Добавляем стили {/*adding-styles*/} -In React, you specify a CSS class with `className`. It works the same way as the HTML [`class`](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/class) attribute: +В React CSS-классы объявляются с помощью свойства `className`. Оно работает аналогично HTML-аттрибуту [`class`](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/class): ```js ``` -Then you write the CSS rules for it in a separate CSS file: +Затем, в отдельном CSS-файле вы прописываете правила для него. ```css -/* In your CSS */ +/* В вашем CSS */ .avatar { border-radius: 50%; } ``` -React does not prescribe how you add CSS files. In the simplest case, you'll add a [``](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link) tag to your HTML. If you use a build tool or a framework, consult its documentation to learn how to add a CSS file to your project. +React не ограничивает вас в способах добавления CSS-файлов. В самом простом случае вы добавляете тэг [``](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link) в ваш HTML-файл. Если вы используете инструмент для сборки или фреймворк, обратитесь к его документации, чтобы понять, как добавить CSS-файл в ваш проект. -## Displaying data {/*displaying-data*/} +## Отображаем данные {/*displaying-data*/} -JSX lets you put markup into JavaScript. Curly braces let you "escape back" into JavaScript so that you can embed some variable from your code and display it to the user. For example, this will display `user.name`: +JSX позволяет вам встраивать разметку в JavaScript, а фигурные скобки позволяют вам "выйти" в JavaScript для того, чтобы вы могли встроить какую-либо переменную из вашего кода и показать ее пользователю. Например, этот код отобразит переменную `user.name`: ```js {3} return ( @@ -124,7 +124,7 @@ return ( ); ``` -You can also "escape into JavaScript" from JSX attributes, but you have to use curly braces *instead of* quotes. For example, `className="avatar"` passes the `"avatar"` string as the CSS class, but `src={user.imageUrl}` reads the JavaScript `user.imageUrl` variable value, and then passes that value as the `src` attribute: +Вы тажке можете "выйти в JavaScript" из атрибутов JSX, но вам нужно использовать фигурные скобки *вместо* кавычек. Например, `className="avatar"` передает строку `"avatar"` как класс CSS, но `src={user.imageUrl}` считывает значение JavaScript-переменной `user.imageUrl` и затем передает его в качестве атрибута `src`: ```js {3,4} return ( @@ -135,7 +135,7 @@ return ( ); ``` -You can put more complex expressions inside the JSX curly braces too, for example, [string concatenation](https://javascript.info/operators#string-concatenation-with-binary): +Вы также можете прописывать более сложные выражения внутри фигурных скобок JSX, например, [сложение строк](https://learn.javascript.ru/operators#slozhenie-strok-pri-pomoschi-binarnogo): @@ -153,7 +153,7 @@ export default function Profile() { {'Photo -In the above example, `style={{}}` is not a special syntax, but a regular `{}` object inside the `style={ }` JSX curly braces. You can use the `style` attribute when your styles depend on JavaScript variables. +В этом примере `style={{}}` не явлется особым синтаксисом, а представляет из себя обычный объект `{}` внутри фигурных скобок JSX `style={ }`. Вы можете использовать атрибут `style` в случаях, когда ваши стили зависят от переменных JavaScript. -## Conditional rendering {/*conditional-rendering*/} +## Условный рендеринг {/*conditional-rendering*/} -In React, there is no special syntax for writing conditions. Instead, you'll use the same techniques as you use when writing regular JavaScript code. For example, you can use an [`if`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/if...else) statement to conditionally include JSX: +В React не существует особого синтаксиса для описания условий, вместо этого пишите привычный вам код на JavaScript. Например, для условного использования JSX-кода можно применять инструкцию [`if`](https://developer.mozilla.org/ru-RU/docs/Web/JavaScript/Reference/Statements/if...else): ```js let content; @@ -196,7 +196,7 @@ return ( ); ``` -If you prefer more compact code, you can use the [conditional `?` operator.](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator) Unlike `if`, it works inside JSX: +Если вы предпочитаете писать более компактный код, используйте [условный оператор `?`.](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator) В отличие от `if`, его можно использовать в JSX: ```js
    @@ -208,7 +208,7 @@ If you prefer more compact code, you can use the [conditional `?` operator.](htt
    ``` -When you don't need the `else` branch, you can also use a shorter [logical `&&` syntax](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_AND#short-circuit_evaluation): +Когда вам не нужно использовать ветку `else`, можно использовать более короткий [логический оператор `&&`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_AND#short-circuit_evaluation): ```js
    @@ -216,23 +216,23 @@ When you don't need the `else` branch, you can also use a shorter [logical `&&`
    ``` -All of these approaches also work for conditionally specifying attributes. If you're unfamiliar with some of this JavaScript syntax, you can start by always using `if...else`. +Все эти способы подходят и для условного задания атрибутов. Если вы не знакомы с такими синтаксическими конструкциями JavaScript, вы можете начать с повсеместного использования `if...else`. -## Rendering lists {/*rendering-lists*/} +## Отрисовываем списки {/*rendering-lists*/} -You will rely on JavaScript features like [`for` loop](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for) and the [array `map()` function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) to render lists of components. +Для отрисовки списков компонентов вам будет нужно использовать такие возможности JavaScript, как [цикл `for`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for) и [функцию массива `map()`](https://developer.mozilla.org/ru-RU/docs/Web/JavaScript/Reference/Global_Objects/Array/map). -For example, let's say you have an array of products: +Например, представим, что у вас есть массив продуктов: ```js const products = [ - { title: 'Cabbage', id: 1 }, - { title: 'Garlic', id: 2 }, - { title: 'Apple', id: 3 }, + { title: 'Капуста', id: 1 }, + { title: 'Чеснок', id: 2 }, + { title: 'Яблоко', id: 3 }, ]; ``` -Inside your component, use the `map()` function to transform an array of products into an array of `
  • ` items: +Преобразуйте этот массив в массив элементов `
  • ` с помощью функции `map()` внутри вашего компонента: ```js const listItems = products.map(product => @@ -246,15 +246,15 @@ return ( ); ``` -Notice how `
  • ` has a `key` attribute. For each item in a list, you should pass a string or a number that uniquely identifies that item among its siblings. Usually, a key should be coming from your data, such as a database ID. React uses your keys to know what happened if you later insert, delete, or reorder the items. +Обратите внимание, что у `
  • ` есть атрибут `key`. Для каждого элемента списка вам нужно задавать ключ в виде строки или числа, который позволит однозначно определить этот элемент среди остальных в списке. Обычно этот ключ берется из ваших данных, например, ключом может быть идентификатор из базы данных. React использует информацию о ключах, чтобы понимать, что случилось, если вы добавите, удалите или переупорядочите элементы. ```js const products = [ - { title: 'Cabbage', isFruit: false, id: 1 }, - { title: 'Garlic', isFruit: false, id: 2 }, - { title: 'Apple', isFruit: true, id: 3 }, + { title: 'Капуста', isFruit: false, id: 1 }, + { title: 'Чеснок', isFruit: false, id: 2 }, + { title: 'Яблоко', isFruit: true, id: 3 }, ]; export default function ShoppingList() { @@ -277,14 +277,14 @@ export default function ShoppingList() { -## Responding to events {/*responding-to-events*/} +## Реагируем на события {/*responding-to-events*/} -You can respond to events by declaring *event handler* functions inside your components: +Можно реагировать на события, объявляя внутри ваших компонентов функции *обработчиков событий*: ```js {2-4,7} function MyButton() { function handleClick() { - alert('You clicked me!'); + alert('Вы нажали на меня!'); } return ( @@ -295,19 +295,19 @@ function MyButton() { } ``` -Notice how `onClick={handleClick}` has no parentheses at the end! Do not _call_ the event handler function: you only need to *pass it down*. React will call your event handler when the user clicks the button. +Заметьте: у `onClick={handleClick}` нет скобок в конце! Не _вызывайте_ функцию обработчика событий: вам нужно просто ее *передать*. React вызовет ваш обработчик событий, когда пользователь нажмет на кнопку. -## Updating the screen {/*updating-the-screen*/} +## Обновляем экран {/*updating-the-screen*/} -Often, you'll want your component to "remember" some information and display it. For example, maybe you want to count the number of times a button is clicked. To do this, add *state* to your component. +Зачастую, вам понадобится, чтобы ваш компонент "помнил" какую-то информацию и отображал её. Например, вы хотите посчитать, сколько раз была нажата кнопка. Чтобы это сделать, добавьте *состояние* в ваш компонент. -First, import [`useState`](/reference/react/useState) from React: +Сначала импортируйте [`useState`](/reference/react/useState) из React: ```js import { useState } from 'react'; ``` -Now you can declare a *state variable* inside your component: +Теперь можно объявить *переменную состояния* внутри вашего компонента: ```js function MyButton() { @@ -315,9 +315,9 @@ function MyButton() { // ... ``` -You’ll get two things from `useState`: the current state (`count`), and the function that lets you update it (`setCount`). You can give them any names, but the convention is to write `[something, setSomething]`. +`useState` вернет вам две сущности: текущее состояние (`count`) и функцию (`setCount`), которая обновляет его. Можно назвать их как вам угодно, но такого рода вещи принято называть `[something, setSomething]`. -The first time the button is displayed, `count` will be `0` because you passed `0` to `useState()`. When you want to change state, call `setCount()` and pass the new value to it. Clicking this button will increment the counter: +На первый показ кнопки `count` будет иметь значение `0`, потому что вы передали `0` в `useState()`. Когда вы хотите изменить состояние, вызовите `setCount()` и передайте туда новое значение. Нажатие на эту кнопку будет увеличивать счётчик: ```js {5} function MyButton() { @@ -329,15 +329,15 @@ function MyButton() { return ( ); } ``` -React will call your component function again. This time, `count` will be `1`. Then it will be `2`. And so on. +React снова вызовет функцию вашего компонента. На этот раз `count` будет равно `1`, затем `2`, и так далее. -If you render the same component multiple times, each will get its own state. Click each button separately: +Если вы рендерите один и тот же компонент несколько раз, у каждого из них будет своё состояние. Попробуйте понажимать на каждую кнопку по отдельности: @@ -347,7 +347,7 @@ import { useState } from 'react'; export default function MyApp() { return (
    -

    Counters that update separately

    +

    Независимо обновляющиеся счётчики

    @@ -363,7 +363,7 @@ function MyButton() { return ( ); } @@ -378,59 +378,59 @@ button {
    -Notice how each button "remembers" its own `count` state and doesn't affect other buttons. +Обратите внимание на то, как каждая кнопка "помнит" свое состояние `count` и не влияет на другие кнопки. -## Using Hooks {/*using-hooks*/} +## Используем хуки {/*using-hooks*/} -Functions starting with `use` are called *Hooks*. `useState` is a built-in Hook provided by React. You can find other built-in Hooks in the [API reference.](/reference/react) You can also write your own Hooks by combining the existing ones. +Функции, которые начинаются с `use`, называются *хуками*. `useState` — это встроенный в React хук. В [справочнике API](/reference/react) приводятся другие встроенные хуки. Также, вы можете писать свои собственные хуки, совмещая уже существующие. -Hooks are more restrictive than other functions. You can only call Hooks *at the top* of your components (or other Hooks). If you want to use `useState` in a condition or a loop, extract a new component and put it there. +У хуков больше ограничений, чем у других функций. Хуки могут вызываться только *в начале* ваших компонентов (или других хуков). Если вам нужен `useState` в условии или цикле, выделите новый компонент и используйте его там. -## Sharing data between components {/*sharing-data-between-components*/} +## Обмениваемся данными между компонентами {/*sharing-data-between-components*/} -In the previous example, each `MyButton` had its own independent `count`, and when each button was clicked, only the `count` for the button clicked changed: +В предыдущем примере у каждого `MyButton` имеется своё собственное состояние `count`, и при нажатии на каждую кнопку обновление `count` происходило только у нажатой кнопки. - + -Initially, each `MyButton`'s `count` state is `0` +В начале у каждого `MyButton` состояние `count` равно `0` - + -The first `MyButton` updates its `count` to `1` +Первый компонент `MyButton` обновляет свой `count` значением `1` -However, often you'll need components to *share data and always update together*. +Однако, вы будете часто сталкиваться с ситуацией, когда вам будет нужно, чтобы компоненты *имели общие данные и всегда обновлялись вместе*. -To make both `MyButton` components display the same `count` and update together, you need to move the state from the individual buttons "upwards" to the closest component containing all of them. +Для того, чтобы оба компонента `MyButton` отображали одно и то же значение `count`, вам нужно выделить состояние из отдельных кнопок "вверх" в ближайший компонент, содержащий эти компоненты. -In this example, it is `MyApp`: +В этом случае таким компонентом является `MyApp`: -Initially, `MyApp`'s `count` state is `0` and is passed down to both children +Сначала состояние `count` компонента `MyApp` равно `0` и передаётся обоим потомкам -On click, `MyApp` updates its `count` state to `1` and passes it down to both children +При нажатии `MyApp` обновляет своё состояние `count` значением `1` и передает его вниз обоим потомкам -Now when you click either button, the `count` in `MyApp` will change, which will change both of the counts in `MyButton`. Here's how you can express this in code. +Теперь, когда вы нажимаете на любую из кнопок, `count` в `MyApp` будет менять своё значение, что в свою очередь повлечёт обновление счётчиков в обоих компонентах `MyButton`. Вот как это можно прописать в коде. -First, *move the state up* from `MyButton` into `MyApp`: +Сначала *переместите вверх состояние* из `MyButton` в `MyApp`: ```js {2-6,18} export default function MyApp() { @@ -442,7 +442,7 @@ export default function MyApp() { return (
    -

    Counters that update separately

    +

    Независимо обновляющиеся счётчики

    @@ -450,12 +450,12 @@ export default function MyApp() { } function MyButton() { - // ... we're moving code from here ... + // ... мы перемещаем код отсюда ... } ``` -Then, *pass the state down* from `MyApp` to each `MyButton`, together with the shared click handler. You can pass information to `MyButton` using the JSX curly braces, just like you previously did with built-in tags like ``: +Затем *передайте состояние на уровень ниже* из `MyApp` каждому `MyButton` вместе с общим обработчиком клика. Можно передавать информацию в `MyButton` через фигурные скобки JSX таким же образом, как вы это делали со встроенными тегами наподобие ``: ```js {11-12} export default function MyApp() { @@ -467,7 +467,7 @@ export default function MyApp() { return (
    -

    Counters that update together

    +

    Совместно обновляющиеся счётчики

    @@ -475,21 +475,21 @@ export default function MyApp() { } ``` -The information you pass down like this is called _props_. Now the `MyApp` component contains the `count` state and the `handleClick` event handler, and *passes both of them down as props* to each of the buttons. +Информация, которую вы передаёте таким образом, называется _пропсами_. Теперь у компонента `MyApp` есть состояние `count` и обработчик событий `handleClick`, *которые он передает в качестве пропсов* каждой кнопке-потомку. -Finally, change `MyButton` to *read* the props you have passed from its parent component: +Наконец, подправьте компонент `MyButton` так, чтобы он *считывал* пропсы, переданные от своего родителя: ```js {1,3} function MyButton({ count, onClick }) { return ( ); } ``` -When you click the button, the `onClick` handler fires. Each button's `onClick` prop was set to the `handleClick` function inside `MyApp`, so the code inside of it runs. That code calls `setCount(count + 1)`, incrementing the `count` state variable. The new `count` value is passed as a prop to each button, so they all show the new value. This is called "lifting state up". By moving state up, you've shared it between components. +Когда вы нажимаете на кнопку, срабатывает обработчик `onClick`. В каждой кнопке в качестве значения пропа `onClick` задана функция `handleClick` из `MyApp`, таким образом, исполняется код этой функции. Этот код вызывает `setCount(count + 1)`, тем самым увеличивая переменную состояния `count`. Новое значение `count` передается в качестве пропа каждой кнопке, таким образом все кнопки будут показывать это новое значение. Это называется "подъёмом состояния вверх". Поднимая состояние вверх, вы делаете его общим для всех компонентов. @@ -530,8 +530,8 @@ button { -## Next Steps {/*next-steps*/} +## Следующие шаги {/*next-steps*/} -By now, you know the basics of how to write React code! +Теперь вы знаете, как писать простой код для React! -Check out the [Tutorial](/learn/tutorial-tic-tac-toe) to put them into practice and build your first mini-app with React. +Ознакомьтесь со следующим [введением](/learn/tutorial-tic-tac-toe), в рамках которого вы примените полученные знания и соберёте свое первое мини-приложение на React. From b06ad4504166ce89cb876145c737d44b60b03813 Mon Sep 17 00:00:00 2001 From: Pavel Zenov Date: Tue, 25 Apr 2023 22:47:05 +0300 Subject: [PATCH 035/233] Translated Quick Start to Russian --- src/content/learn/index.md | 72 +++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/src/content/learn/index.md b/src/content/learn/index.md index 08aa2b57c..e7dda8f35 100644 --- a/src/content/learn/index.md +++ b/src/content/learn/index.md @@ -4,7 +4,7 @@ title: Quick Start -Добро пожаловать в документацию React! Эта страница послужит вам введением в 80% концептов React, которые вы будете использовать каждый день. +Добро пожаловать в документацию React! Эта страница посвятит вас в основы 80% концепций React, которыми вы будете пользоваться каждый день. @@ -18,11 +18,11 @@ title: Quick Start -## Creating and nesting components {/*components*/} +## Создание и вложение компонентов {/*components*/} Приложения на React собираются из *компонентов*. Компонент — это часть пользовательского интерфейса, у которой есть свои логика и внешность. Компоненты в размерах разнятся от мелких кнопок до больших цельных страниц. -Компоненты React — это Javascript-функции, которые возвращают разметку: +Компоненты React — это функции JavaScript, которые возвращают разметку: ```js function MyButton() { @@ -32,7 +32,7 @@ function MyButton() { } ``` -Теперь, когда вы объявили `MyButton`, вы можете вложить его в другой компонент: +Вы объявили компонент `MyButton`, который можно вложить в другой компонент: ```js {5} export default function MyApp() { @@ -45,7 +45,7 @@ export default function MyApp() { } ``` -Заметьте, что `` начинается с заглавной буквы. Это отличительная черта компонентов React. Названия компонентов в React должны всегда начинаться с заглавной буквы, а теги HTML — с маленькой. +Обратите внимание на то, что `` начинается с заглавной буквы. Это отличительная черта компонентов React. Названия компонентов в React всегда должны начинаться с заглавной буквы, а теги HTML — с маленькой. Посмотрите на результат: @@ -72,11 +72,11 @@ export default function MyApp() { -Ключевые слова `export default` указывают на основной компонент в файле. Если вам не знакомы некоторые аспекты синтаксиса JavaScript, [MDN](https://developer.mozilla.org/ru-RU/docs/web/javascript/reference/statements/export) и [learn.javascript.ru](https://learn.javascript.ru/import-export) послужат для вас хорошими справочниками. +Ключевые слова `export default` указывают на основной компонент в файле. Для того, чтобы понять некоторые особенности синтаксиса JavaScript, можно пользоваться ресурсами [MDN](https://developer.mozilla.org/ru-RU/docs/web/javascript/reference/statements/export) и [learn.javascript.ru](https://learn.javascript.ru/import-export). -## Пишем разметку с JSX {/*writing-markup-with-jsx*/} +## Написание разметки с JSX {/*writing-markup-with-jsx*/} -Используемый в примерах выше синтаксис разметки называется *JSX*. Его необязательно использовать, но большинство проектов на React используют JSX в силу его удобства. Все [инструменты, которые мы рекомендуем для локальной разработки,](/learn/installation) поддерживают JSX из коробки. +Используемый в примерах выше синтаксис разметки называется *JSX*. Он не обязателен, но большинство проектов на React предпочитают его использовать за удобство. Все [инструменты, которые мы рекомендуем для локальной разработки,](/learn/installation) поддерживают JSX из коробки. JSX строже HTML. Вам нужно закрывать теги вроде `
    `. Ваш компонент также не может возвращать несколько JSX-тегов. Их нужно будет обернуть внутрь общего родителя, например, `
    ...
    ` или пустую обёртку вида `<>...`: @@ -91,17 +91,17 @@ function AboutPage() { } ``` -Если вам нужно перевести большое количество HTML-верстки в JSX, вы можете использовать [онлайн-конвертер.](https://transform.tools/html-to-jsx) +Для того, чтобы перевести большое количество HTML-верстки в JSX, можно использовать [онлайн-конвертер.](https://transform.tools/html-to-jsx) -## Добавляем стили {/*adding-styles*/} +## Добавление стилей {/*adding-styles*/} -В React CSS-классы объявляются с помощью свойства `className`. Оно работает аналогично HTML-аттрибуту [`class`](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/class): +В React CSS-классы объявляются с помощью свойства `className`. Оно работает аналогично HTML-аттрибуту [`class`](https://developer.mozilla.org/ru-RU/docs/Web/HTML/Global_attributes/class): ```js ``` -Затем, в отдельном CSS-файле вы прописываете правила для него. +В отдельном CSS-файле вы прописываете стили для него. ```css /* В вашем CSS */ @@ -110,9 +110,9 @@ function AboutPage() { } ``` -React не ограничивает вас в способах добавления CSS-файлов. В самом простом случае вы добавляете тэг [``](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link) в ваш HTML-файл. Если вы используете инструмент для сборки или фреймворк, обратитесь к его документации, чтобы понять, как добавить CSS-файл в ваш проект. +React не ограничивает вас в том, как добавлять CSS-файлы. В самом простом случае вы добавляете тэг [``](https://developer.mozilla.org/ru-RU/docs/Web/HTML/Element/link) в ваш HTML-файл. Если вы используете инструмент для сборки или фреймворк, обратитесь к его документации, чтобы понять, как добавить CSS-файл в ваш проект. -## Отображаем данные {/*displaying-data*/} +## Отображение данных {/*displaying-data*/} JSX позволяет вам встраивать разметку в JavaScript, а фигурные скобки позволяют вам "выйти" в JavaScript для того, чтобы вы могли встроить какую-либо переменную из вашего кода и показать ее пользователю. Например, этот код отобразит переменную `user.name`: @@ -196,7 +196,7 @@ return ( ); ``` -Если вы предпочитаете писать более компактный код, используйте [условный оператор `?`.](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator) В отличие от `if`, его можно использовать в JSX: +Если вы предпочитаете писать более компактный код, используйте [условный оператор `?`.](https://developer.mozilla.org/ru-RU/docs/Web/JavaScript/Reference/Operators/Conditional_Operator) В отличие от `if` его можно использовать в JSX: ```js
    @@ -208,7 +208,7 @@ return (
    ``` -Когда вам не нужно использовать ветку `else`, можно использовать более короткий [логический оператор `&&`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_AND#short-circuit_evaluation): +Когда вам не нужна ветка `else`, можно использовать более короткий [логический оператор `&&`](https://developer.mozilla.org/ru-RU/docs/Web/JavaScript/Reference/Operators/Logical_AND#short-circuit_evaluation): ```js
    @@ -216,11 +216,11 @@ return (
    ``` -Все эти способы подходят и для условного задания атрибутов. Если вы не знакомы с такими синтаксическими конструкциями JavaScript, вы можете начать с повсеместного использования `if...else`. +Все эти способы подходят и для условного задания атрибутов. Если вам не знакомы такие синтаксические конструкции JavaScript, вы можете начать с повсеместного использования `if...else`. -## Отрисовываем списки {/*rendering-lists*/} +## Рендеринг списков {/*rendering-lists*/} -Для отрисовки списков компонентов вам будет нужно использовать такие возможности JavaScript, как [цикл `for`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for) и [функцию массива `map()`](https://developer.mozilla.org/ru-RU/docs/Web/JavaScript/Reference/Global_Objects/Array/map). +Для отрисовки списков компонентов вам будет нужно использовать такие возможности JavaScript, как [цикл `for`](https://developer.mozilla.org/ru-RU/docs/Web/JavaScript/Reference/Statements/for) и [функция массива `map()`](https://developer.mozilla.org/ru-RU/docs/Web/JavaScript/Reference/Global_Objects/Array/map). Например, представим, что у вас есть массив продуктов: @@ -277,7 +277,7 @@ export default function ShoppingList() { -## Реагируем на события {/*responding-to-events*/} +## Обработка событий {/*responding-to-events*/} Можно реагировать на события, объявляя внутри ваших компонентов функции *обработчиков событий*: @@ -295,11 +295,11 @@ function MyButton() { } ``` -Заметьте: у `onClick={handleClick}` нет скобок в конце! Не _вызывайте_ функцию обработчика событий: вам нужно просто ее *передать*. React вызовет ваш обработчик событий, когда пользователь нажмет на кнопку. +Заметьте: у `onClick={handleClick}` нет скобок в конце! Не _вызывайте_ функцию обработчика событий: вам нужно просто ее *передать*. React вызовет ваш обработчик событий, когда пользователь кликнет по кнопке. -## Обновляем экран {/*updating-the-screen*/} +## Обновление экрана {/*updating-the-screen*/} -Зачастую, вам понадобится, чтобы ваш компонент "помнил" какую-то информацию и отображал её. Например, вы хотите посчитать, сколько раз была нажата кнопка. Чтобы это сделать, добавьте *состояние* в ваш компонент. +Вам может понадобиться, чтобы ваш компонент "помнил" какую-то информацию и отображал её. Например, вы хотите посчитать, сколько раз была нажата кнопка. Чтобы это сделать, добавьте *состояние* в ваш компонент. Сначала импортируйте [`useState`](/reference/react/useState) из React: @@ -317,7 +317,7 @@ function MyButton() { `useState` вернет вам две сущности: текущее состояние (`count`) и функцию (`setCount`), которая обновляет его. Можно назвать их как вам угодно, но такого рода вещи принято называть `[something, setSomething]`. -На первый показ кнопки `count` будет иметь значение `0`, потому что вы передали `0` в `useState()`. Когда вы хотите изменить состояние, вызовите `setCount()` и передайте туда новое значение. Нажатие на эту кнопку будет увеличивать счётчик: +На первый показ кнопки `count` будет иметь значение `0`, потому что вы передали `0` в `useState()`. Когда вы хотите изменить состояние, вызовите `setCount()` и передайте туда новое значение. Клик на эту кнопку будет увеличивать счётчик: ```js {5} function MyButton() { @@ -329,7 +329,7 @@ function MyButton() { return ( ); } @@ -337,7 +337,7 @@ function MyButton() { React снова вызовет функцию вашего компонента. На этот раз `count` будет равно `1`, затем `2`, и так далее. -Если вы рендерите один и тот же компонент несколько раз, у каждого из них будет своё состояние. Попробуйте понажимать на каждую кнопку по отдельности: +Если вы рендерите один и тот же компонент несколько раз, то у каждого из них будет своё состояние. Попробуйте покликать на каждую кнопку по отдельности: @@ -363,7 +363,7 @@ function MyButton() { return ( ); } @@ -380,15 +380,15 @@ button { Обратите внимание на то, как каждая кнопка "помнит" свое состояние `count` и не влияет на другие кнопки. -## Используем хуки {/*using-hooks*/} +## Использование хуков {/*using-hooks*/} Функции, которые начинаются с `use`, называются *хуками*. `useState` — это встроенный в React хук. В [справочнике API](/reference/react) приводятся другие встроенные хуки. Также, вы можете писать свои собственные хуки, совмещая уже существующие. У хуков больше ограничений, чем у других функций. Хуки могут вызываться только *в начале* ваших компонентов (или других хуков). Если вам нужен `useState` в условии или цикле, выделите новый компонент и используйте его там. -## Обмениваемся данными между компонентами {/*sharing-data-between-components*/} +## Обмен данными между компонентами {/*sharing-data-between-components*/} -В предыдущем примере у каждого `MyButton` имеется своё собственное состояние `count`, и при нажатии на каждую кнопку обновление `count` происходило только у нажатой кнопки. +В предыдущем примере у каждого `MyButton` имеется своё собственное состояние `count`, и при клике на каждую кнопку обновление `count` происходило только у нажатой кнопки. @@ -398,7 +398,7 @@ button { - + Первый компонент `MyButton` обновляет свой `count` значением `1` @@ -414,15 +414,15 @@ button { - + Сначала состояние `count` компонента `MyApp` равно `0` и передаётся обоим потомкам - + -При нажатии `MyApp` обновляет своё состояние `count` значением `1` и передает его вниз обоим потомкам +При клике `MyApp` обновляет своё состояние `count` значением `1` и передает его вниз обоим потомкам @@ -483,7 +483,7 @@ export default function MyApp() { function MyButton({ count, onClick }) { return ( ); } @@ -534,4 +534,4 @@ button { Теперь вы знаете, как писать простой код для React! -Ознакомьтесь со следующим [введением](/learn/tutorial-tic-tac-toe), в рамках которого вы примените полученные знания и соберёте свое первое мини-приложение на React. +Ознакомьтесь с [введением](/learn/tutorial-tic-tac-toe), в рамках которого вы примените полученные знания и соберёте свое первое мини-приложение на React. From 22019813d2c727e2c22db431ed84f2fa0f3d6c99 Mon Sep 17 00:00:00 2001 From: XamzatJR Date: Tue, 25 Apr 2023 23:55:29 +0300 Subject: [PATCH 036/233] translate Fragment page --- src/content/reference/react/Fragment.md | 58 ++++++++++++------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/src/content/reference/react/Fragment.md b/src/content/reference/react/Fragment.md index 638450405..9926088a3 100644 --- a/src/content/reference/react/Fragment.md +++ b/src/content/reference/react/Fragment.md @@ -4,7 +4,7 @@ title: (<>...) -``, often used via `<>...` syntax, lets you group elements without a wrapper node. +``, часто используемый с помощью синтаксиса `<>...`, позволяет группировать элементы без создания оберточного узла. ```js <> @@ -19,29 +19,29 @@ title: (<>...) --- -## Reference {/*reference*/} +## Справочник {/*reference*/} ### `` {/*fragment*/} -Wrap elements in `` to group them together in situations where you need a single element. Grouping elements in `Fragment` has no effect on the resulting DOM; it is the same as if the elements were not grouped. The empty JSX tag `<>` is shorthand for `` in most cases. +Оберните элементы в ``, чтобы сгруппировать их вместе в тех случаях, когда вам необходим единственный элемент. Группировка элементов с помощью `Fragment` не влияет на конечный DOM; он остается таким же, как если бы элементы не были сгруппированы. Пустой JSX тег `<>` в большинстве случаев является сокращением для ``. -#### Props {/*props*/} +#### Пропсы {/*props*/} -- **optional** `key`: Fragments declared with the explicit `` syntax may have [keys.](/learn/rendering-lists#keeping-list-items-in-order-with-key) +- **необязательный** `key`: Фрагменты объявленные с помощью явного синтаксиса `` могут иметь [ключи.](/learn/rendering-lists#keeping-list-items-in-order-with-key) -#### Caveats {/*caveats*/} +#### Предостережения {/*caveats*/} -- If you want to pass `key` to a Fragment, you can't use the `<>...` syntax. You have to explicitly import `Fragment` from `'react'` and render `...`. +- Если вам необходимо передать `key` фрагменту, вы не можете использовать краткий синтаксис `<>...`. Вы должны явно импортировать `Fragment` из `'react'` и рендерить `...`. -- React does not [reset state](/learn/preserving-and-resetting-state) when you go from rendering `<>` to `[]` or back, or when you go from rendering `<>` to `` and back. This only works a single level deep: for example, going from `<><>` to `` resets the state. See the precise semantics [here.](https://gist.github.com/clemmy/b3ef00f9507909429d8aa0d3ee4f986b) +- React не [сбрасывает состояние](/learn/preserving-and-resetting-state) когда вы переключаетесь между рендерингом `<>` к `[]` или обратно, или между `<>` и ``. Однако, это работает только на одном уровне вложенности. Например, когда вы переключаетесь от `<><>` к ``, то состояние будет сброшено. Точную семантику можно посмотреть [здесь.](https://gist.github.com/clemmy/b3ef00f9507909429d8aa0d3ee4f986b) --- -## Usage {/*usage*/} +## Применение {/*usage*/} -### Returning multiple elements {/*returning-multiple-elements*/} +### Возвращение нескольких элементов {/*returning-multiple-elements*/} -Use `Fragment`, or the equivalent `<>...` syntax, to group multiple elements together. You can use it to put multiple elements in any place where a single element can go. For example, a component can only return one element, but by using a Fragment you can group multiple elements together and then return them as a group: +Используйте `Fragment` или аналогичный синтаксис `<>...`, чтобы сгруппировать несколько элементов. Вы можете использовать его для размещения нескольких элементов в любом месте, где может находиться один элемент. Например, компонент может возвращать только один элемент, но используя Fragment, вы можете сгруппировать несколько элементов вместе и затем вернуть их как группу: ```js {3,6} function Post() { @@ -54,7 +54,7 @@ function Post() { } ``` -Fragments are useful because grouping elements with a Fragment has no effect on layout or styles, unlike if you wrapped the elements in another container like a DOM element. If you inspect this example with the browser tools, you'll see that all `

    ` and `

    ` DOM nodes appear as siblings without wrappers around them: +Фрагменты полезны тем, что группировка элементов с их помощью не влияет на отображение элементов на странице или стили, в отличие от случая, когда вы оборачиваете элементы в другой контейнер, например, в DOM элемент. Если вы осмотрите этот пример с помощью инструментов браузера, то увидите, что все DOM узлы `

    ` и `

    ` отображаются как соседи без оберток вокруг них: @@ -62,8 +62,8 @@ Fragments are useful because grouping elements with a Fragment has no effect on export default function Blog() { return ( <> - - + + ) } @@ -94,9 +94,9 @@ function PostBody({ body }) { -#### How to write a Fragment without the special syntax? {/*how-to-write-a-fragment-without-the-special-syntax*/} +#### Как написать фрагмент без использования особого синтаксиса? {/*how-to-write-a-fragment-without-the-special-syntax*/} -The example above is equivalent to importing `Fragment` from React: +Приведенный выше пример эквивалентен импорту `Fragment` из React: ```js {1,5,8} import { Fragment } from 'react'; @@ -111,15 +111,15 @@ function Post() { } ``` -Usually you won't need this unless you need to [pass a `key` to your `Fragment`.](#rendering-a-list-of-fragments) +В большинстве случаев это не нужно, за исключением ситуаций, когда необходимо [передать `key` фрагменту.](#rendering-a-list-of-fragments) --- -### Assigning multiple elements to a variable {/*assigning-multiple-elements-to-a-variable*/} +### Присвоение переменной нескольких элементов {/*assigning-multiple-elements-to-a-variable*/} -Like any other element, you can assign Fragment elements to variables, pass them as props, and so on: +Как и любой другой элемент, вы можете присваивать элементы `Fragment` переменным, передавать их в качестве пропсов и так далее: ```js function CloseDialog() { @@ -131,7 +131,7 @@ function CloseDialog() { ); return ( - Are you sure you want to leave this page? + Вы уверены, что хотите покинуть эту страницу? ); } @@ -139,17 +139,17 @@ function CloseDialog() { --- -### Grouping elements with text {/*grouping-elements-with-text*/} +### Группировка элементов с текстом {/*grouping-elements-with-text*/} -You can use `Fragment` to group text together with components: +Вы можете использовать `Fragment` чтобы сгруппировать текст вместе с компонентами: ```js function DateRangePicker({ start, end }) { return ( <> - From + С - to + до ); @@ -158,9 +158,9 @@ function DateRangePicker({ start, end }) { --- -### Rendering a list of Fragments {/*rendering-a-list-of-fragments*/} +### Рендеринг списка фрагментов {/*rendering-a-list-of-fragments*/} -Here's a situation where you need to write `Fragment` explicitly instead of using the `<>` syntax. When you [render multiple elements in a loop](/learn/rendering-lists), you need to assign a `key` to each element. If the elements within the loop are Fragments, you need to use the normal JSX element syntax in order to provide the `key` attribute: +Рассмотрим ситуацию, когда вам нужно явно написать `Fragment`, вместо использования синтаксиса `<>`. Это может понадобиться, когда вы [рендерите несколько элементов в цикле](/learn/rendering-lists) и каждому элементу нужно присвоить `key`. Если элементы в цикле являются фрагментами, то вам необходимо использовать стандартный синтаксис JSX элементов, чтобы предоставить атрибут `key`: ```js {3,6} function Blog() { @@ -173,7 +173,7 @@ function Blog() { } ``` -You can inspect the DOM to verify that there are no wrapper elements around the Fragment children: +Вы можете осмотреть DOM, чтобы убедиться, что вокруг дочерних элементов фрагмента нет оберток: @@ -181,8 +181,8 @@ You can inspect the DOM to verify that there are no wrapper elements around the import { Fragment } from 'react'; const posts = [ - { id: 1, title: 'An update', body: "It's been a while since I posted..." }, - { id: 2, title: 'My new blog', body: 'I am starting a new blog!' } + { id: 1, title: 'Обновление', body: "Давненько я не писал..." }, + { id: 2, title: 'Мой новый блог', body: 'Я начинаю новый блог!' } ]; export default function Blog() { From 82dbbe194a5af437661e4bc392c637ebab6b4a39 Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Wed, 26 Apr 2023 02:42:15 +0300 Subject: [PATCH 037/233] Update conditional-rendering.md typo fix --- src/content/learn/conditional-rendering.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/conditional-rendering.md b/src/content/learn/conditional-rendering.md index 628c7b70f..d8904dd77 100644 --- a/src/content/learn/conditional-rendering.md +++ b/src/content/learn/conditional-rendering.md @@ -4,7 +4,7 @@ title: Условный рендеринг -Вашим компонентам нужно часто отображать различные вещи в зависимости от различных условий. В React вы можете реденрить JSX в зависимости от его условий, используя JavaScript операторы. Такие, как `if`, `&&` и `? :` +Вашим компонентам нужно часто отображать различные вещи в зависимости от различных условий. В React вы можете рендерить JSX в зависимости от его условий, используя JavaScript операторы. Такие, как `if`, `&&` и `? :` From 4df1d7bf23bca22b76fb41a76791477080f755e3 Mon Sep 17 00:00:00 2001 From: Maxim Titov Date: Wed, 26 Apr 2023 11:01:24 +0600 Subject: [PATCH 038/233] translate Start a new React project page --- .../learn/start-a-new-react-project.md | 81 ++++++++++--------- src/sidebarLearn.json | 4 +- 2 files changed, 43 insertions(+), 42 deletions(-) diff --git a/src/content/learn/start-a-new-react-project.md b/src/content/learn/start-a-new-react-project.md index 280a1378e..7e2326c0a 100644 --- a/src/content/learn/start-a-new-react-project.md +++ b/src/content/learn/start-a-new-react-project.md @@ -1,126 +1,127 @@ --- -title: Start a New React Project +title: Создаём новый проект с React --- -If you want to build a new app or a new website fully with React, we recommend picking one of the React-powered frameworks popular in the community. Frameworks provide features that most apps and sites eventually need, including routing, data fetching, and generating HTML. +Если вы хотите создать новое приложение или веб-сайт с React, мы советуем начать с одного из уже зарекомендовавших себя фреймворков. Фреймворки дают возможности, которые нужны большинству сайтов, включая маршрутизацию, загрузку данных и генерацию HTML. -**You need to install [Node.js](https://nodejs.org/en/) for local development.** You can *also* choose to use Node.js in production, but you don't have to. Many React frameworks support export to a static HTML/CSS/JS folder. +**Вам потребуется установить [Node.js](https://nodejs.org/ru/) для локальной разработки.** Вы можете использовать Node.js и в продакшене, но это необязательно. Многие React-фреймворки экспортируют ваш код в статические HTML/CSS/JS файлы. -## Production-grade React frameworks {/*production-grade-react-frameworks*/} +## Рекомендуемые React-фреймворки {/*production-grade-react-frameworks*/} ### Next.js {/*nextjs*/} -**[Next.js](https://nextjs.org/) is a full-stack React framework.** It's versatile and lets you create React apps of any size--from a mostly static blog to a complex dynamic application. To create a new Next.js project, run in your terminal: +**[Next.js](https://nextjs.org/) -- универсальный фулстек-фреймворк.** С его помощью вы можете создавать сайты любого размера от простого статического блога до сложного динамического приложения. Для создания нового Next.js проекта выполните команду в терминале: npx create-next-app -If you're new to Next.js, check out the [Next.js tutorial.](https://nextjs.org/learn/foundations/about-nextjs) +Узнайте больше о Next.js из [официальной документации.](https://nextjs.org/learn/foundations/about-nextjs) -Next.js is maintained by [Vercel](https://vercel.com/). You can [deploy a Next.js app](https://nextjs.org/docs/deployment) to any Node.js or serverless hosting, or to your own server. [Fully static Next.js apps](https://nextjs.org/docs/advanced-features/static-html-export) can be deployed to any static hosting. +Команда [Vercel](https://vercel.com/) постоянно улучшает Next.js. Вы можете [развернуть Next.js приложение](https://nextjs.org/docs/deployment) на облачном хостинге с Node.js или бессерверными вычислениями, а также на вашем собственном сервере. [Полностью статические Next.js приложения](https://nextjs.org/docs/advanced-features/static-html-export) могут быть опубликованы на любом статическом хостинге. ### Remix {/*remix*/} -**[Remix](https://remix.run/) is a full-stack React framework with nested routing.** It lets you break your app into nested parts that can load data in parallel and refresh in response to the user actions. To create a new Remix project, run: +**[Remix](https://remix.run/) -- фулстек-фреймворк с вложенной маршрутизацией.** Он помогает разбить приложение на вложенные части, которые могут загружать данные параллельно и обновлять приложение, реагируя на действия пользователя. Чтобы создать новый Remix-проект, выполните в терминале команду: npx create-remix -If you're new to Remix, check out the Remix [blog tutorial](https://remix.run/docs/en/main/tutorials/blog) (short) and [app tutorial](https://remix.run/docs/en/main/tutorials/jokes) (long). +Для знакомства с Remix вы можете пройти их руководства по созданию [блога](https://remix.run/docs/ru/main/tutorials/blog) (короткое) и [приложения](https://remix.run/docs/ru/main/tutorials/jokes) (длинное). -Remix is maintained by [Shopify](https://www.shopify.com/). When you create a Remix project, you need to [pick your deployment target](https://remix.run/docs/en/main/guides/deployment). You can deploy a Remix app to any Node.js or serverless hosting by using or writing an [adapter](https://remix.run/docs/en/main/other-api/adapter). +Remix поддерживается командой [Shopify](https://www.shopify.com/). Когда вы создаёте проект с помощью Remix, вам необходимо [выбрать шаблон для развёртывания приложения](https://remix.run/docs/ru/main/guides/deployment). Вы можете развернуть Remix-приложение на облачном хостинге с Node.js или бессерверными вычислениями, использовав готовый или написав собственный [адаптер](https://remix.run/docs/ru/main/other-api/adapter). ### Gatsby {/*gatsby*/} -**[Gatsby](https://www.gatsbyjs.com/) is a React framework for fast CMS-backed websites.** Its rich plugin ecosystem and its GraphQL data layer simplify integrating content, APIs, and services into one website. To create a new Gatsby project, run: +**[Gatsby](https://www.gatsbyjs.com/) -- React-фреймворк для создания быстрых веб-сайтов с поддержкой CMS.** Обширная коллекция плагинов и слой данных GraphQL позволяют наполнять веб-сайт содержимым, а также интегрировать различные API и сервисы. Чтобы создать новый Gatsby-проект, выполните в терминале команду: npx create-gatsby -If you're new to Gatsby, check out the [Gatsby tutorial.](https://www.gatsbyjs.com/docs/tutorial/) +Для первого знакомства с Gatsby начните с [введения.](https://www.gatsbyjs.com/docs/tutorial/) -Gatsby is maintained by [Netlify](https://www.netlify.com/). You can [deploy a fully static Gatsby site](https://www.gatsbyjs.com/docs/how-to/previews-deploys-hosting) to any static hosting. If you opt into using server-only features, make sure your hosting provider supports them for Gatsby. +Gatsby поддерживается командой [Netlify](https://www.netlify.com/). При помощи Gatsby вы можете [развернуть полностью статический веб-сайт](https://www.gatsbyjs.com/docs/how-to/previews-deploys-hosting) на любом статическом хостинге. Если вы хотите использовать только серверные возможности Gatsby, убедитесь что ваш хостинг их поддерживает. -### Expo (for native apps) {/*expo*/} +### Expo (для нативных приложений) {/*expo*/} -**[Expo](https://expo.dev/) is a React framework that lets you create universal Android, iOS, and web apps with truly native UIs.** It provides an SDK for [React Native](https://reactnative.dev/) that makes the native parts easier to use. To create a new Expo project, run: +**[Expo](https://expo.dev/) -- React-фреймворк, который позволяет создавать универсальные приложения с нативными интерфейсами для Android, iOS и браузеров.** Он идёт вместе с SDK для [React Native](https://reactnative.dev/) и облегчает разработку нативных частей. Чтобы создать новый проект с Expo, запустите в терминале команду: npx create-expo-app -If you're new to Expo, check out the [Expo tutorial](https://docs.expo.dev/tutorial/introduction/). +Чтобы узнать больше, ознакомьтесь с [руководством по Expo](https://docs.expo.dev/tutorial/introduction/). -Expo is maintained by [Expo (the company)](https://expo.dev/about). Building apps with Expo is free, and you can submit them to the Google and Apple app stores without restrictions. Expo additionally provides opt-in paid cloud services. +Фреймворк поддерживается командой [Expo](https://expo.dev/about). Вы можете бесплатно создавать приложения с помощью Expo и добавлять их в магазины Apple и Google без каких-либо ограничений. Дополнительно Expo предлагает платные облачные сервисы. -#### Can I use React without a framework? {/*can-i-use-react-without-a-framework*/} +#### Можно ли использовать React без фреймворка? {/*can-i-use-react-without-a-framework*/} -You can definitely use React without a framework--that's how you'd [use React for a part of your page.](/learn/add-react-to-an-existing-project#using-react-for-a-part-of-your-existing-page) **However, if you're building a new app or a site fully with React, we recommend using a framework.** +Конечно! Так, например, вы можете [использовать React только для определённой части страницы.](/learn/add-react-to-an-existing-project#using-react-for-a-part-of-your-existing-page) **Однако, если вы создаёте приложение или веб-сайт с нуля, мы рекомендуем взять один из фреймворков.** -Here's why. +И вот почему. -Even if you don't need routing or data fetching at first, you'll likely want to add some libraries for them. As your JavaScript bundle grows with every new feature, you might have to figure out how to split code for every route individually. As your data fetching needs get more complex, you are likely to encounter server-client network waterfalls that make your app feel very slow. As your audience includes more users with poor network conditions and low-end devices, you might need to generate HTML from your components to display content early--either on the server, or during the build time. Changing your setup to run some of your code on the server or during the build can be very tricky. +Даже если поначалу вам не понадобились маршрутизация или загрузка данных, скорее всего вы захотите добавить библиотеки для их поддержки позже. Ваш JavaScript бандл будет расти вместе с вашим приложением, и вам придётся задуматься как разделять код для разных маршрутов. Ваше приложение будет загружать всё больше данных, и в итоге вы можете столкнуться с каскадными запросами, которые замедлят ваше приложение. Среди ваших пользователей появятся те, кто пользуется низкоскоростным интернетом или старыми устройствами, и вы захотите генерировать HTML на сервере или во время сборки. Поменять настройки большого проекта так, чтобы запускать код на сервере, может оказаться затруднительным. -**These problems are not React-specific. This is why Svelte has SvelteKit, Vue has Nuxt, and so on.** To solve these problems on your own, you'll need to integrate your bundler with your router and with your data fetching library. It's not hard to get an initial setup working, but there are a lot of subtleties involved in making an app that loads quickly even as it grows over time. You'll want to send down the minimal amount of app code but do so in a single client–server roundtrip, in parallel with any data required for the page. You'll likely want the page to be interactive before your JavaScript code even runs, to support progressive enhancement. You may want to generate a folder of fully static HTML files for your marketing pages that can be hosted anywhere and still work with JavaScript disabled. Building these capabilities yourself takes real work. +**Эти проблемы не являются специфичными для React. У Svelte есть SvelteKit, у Vue -- Nuxt, и т.д.** Чтобы решить эти проблемы, вам придётся интегрировать ваш бандлер с выбранными библиотеками для маршрутизации и загрузки данных. Сделать первичную настройку и заставить всё это работать вместе может оказаться не так сложно, но вам придётся поддерживать производительность приложения по мере его роста и узнать о множестве подводных камней. Вы захотите отправлять как можно меньше кода, и в то же время уменьшить количество взаимодействий между клиентом и сервером, а ещё параллельно загружать необходимые для страницы данные. Вы можете захотеть, чтобы страница была интерактивной ещё до запуска Javascript-кода, и пользователи любых браузеров могли работать с ней одинаково. Или вам потребуется добавить папку статических HTML-файлов для маркетинговых страниц, которые могут работать с отключённым на странице Javascript. Поддержка этих возможностей требует большого труда. -**React frameworks on this page solve problems like these by default, with no extra work from your side.** They let you start very lean and then scale your app with your needs. Each React framework has a community, so finding answers to questions and upgrading tooling is easier. Frameworks also give structure to your code, helping you and others retain context and skills between different projects. Conversely, with a custom setup it's easier to get stuck on unsupported dependency versions, and you'll essentially end up creating your own framework—albeit one with no community or upgrade path (and if it's anything like the ones we've made in the past, more haphazardly designed). +**Рекомендованные React-фреймворки помогают решить эти проблемы из коробки и не требуют от вас дополнительных усилий.** Вы можете начать с малого и добавлять необходимую функциональность по мере необходимости. У каждого фреймворка есть сообщество, которое поможет найти ответы на ваши вопросы и без труда обновляться до новых версий. Кроме того, фреймворки помогают структурировать ваш код и делают его понятным для других разработчиков. Верно и обратное, сделав собственное решение, есть риск застрять на поддержке зависимостей и в результате создать свой собственный фреймворк без сообщества и пути развития (и, скорее всего, он окажется спроектирован хуже чем уже существующие решения от команд, которые посвятили этим проблемам большое количество времени). -If you're still not convinced, or your app has unusual constraints not served well by these frameworks and you'd like to roll your own custom setup, we can't stop you--go for it! Grab `react` and `react-dom` from npm, set up your custom build process with a bundler like [Vite](https://vitejs.dev/) or [Parcel](https://parceljs.org/), and add other tools as you need them for routing, static generation or server-side rendering, and more. +Если мы не смогли вас убедить, или при разработке вы столкнулись с необычными ситуациями, для которых эти фреймворки не предлагают решений, мы не вправе вас останавливать - создайте свою конфигурацию! Установите `react` и `react-dom` из npm, настройте свою собственную сборку с бандлерами, такими как [Vite](https://vitejs.dev/) или [Parcel](https://parceljs.org/), и добавьте все необходимые инструменты для маршрутизации, статической генерации кода, серверного рендеринга или любые другие. -## Bleeding-edge React frameworks {/*bleeding-edge-react-frameworks*/} +## Новейшие React-фреймворки {/*bleeding-edge-react-frameworks*/} -As we've explored how to continue improving React, we realized that integrating React more closely with frameworks (specifically, with routing, bundling, and server technologies) is our biggest opportunity to help React users build better apps. The Next.js team has agreed to collaborate with us in researching, developing, integrating, and testing framework-agnostic bleeding-edge React features like [React Server Components.](/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023#react-server-components) +По мере того как мы развивали React, мы поняли, что лучшая интеграция с фреймворками (особенно в вопросах маршрутизации, сборки и серверных технологий) принесёт наибольшую пользу нашим пользователям. Команда Next.js согласилась взаимодействовать с нами в поиске, разработке, внедрении и тестировании новейших подходов, которые не зависят от конкретного фреймворка, например [серверные React-компоненты.](/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023#react-server-components) -These features are getting closer to being production-ready every day, and we've been in talks with other bundler and framework developers about integrating them. Our hope is that in a year or two, all frameworks listed on this page will have full support for these features. (If you're a framework author interested in partnering with us to experiment with these features, please let us know!) +Мы работаем над тем, чтобы новые возможности стали доступны в продакшене как можно скорее, и договариваемся с разработчиками бандлеров и фреймворков об их интеграции. Мы рассчитываем, что через год-два все перечисленные фреймворки будут полностью поддерживать эти возможности. (Если вы разработчик фреймворка и хотите помочь нам в экспериментах, пожалуйста, дайте нам знать!) -### Next.js (App Router) {/*nextjs-app-router*/} +### Next.js (Маршрутизатор приложения) {/*nextjs-app-router*/} -**[Next.js's App Router](https://beta.nextjs.org/docs/getting-started) is a redesign of the Next.js APIs aiming to fulfill the React team’s full-stack architecture vision.** It lets you fetch data in asynchronous components that run on the server or even during the build. +**[Маршрутизатор приложения Next.js (Next.js App Router)](https://beta.nextjs.org/docs/getting-started) -- обновлённый API Next.js, отвечающий тому, как команда React видит архитектуру фулстек-приложений сегодня.** Маршрутизатор позволяет загружать данные в асинхронных компонентах на сервере или во время сборки. + +Команда [Vercel](https://vercel.com/) постоянно улучшает Next.js. Вы можете [развернуть Next.js приложение](https://nextjs.org/docs/deployment) на облачном хостинге с Node.js или бессерверными вычислениями, а также на вашем собственном сервере. Next.js также поддерживает [статический экспорт](https://beta.nextjs.org/docs/configuring/static-export), который не требует сервера. -Next.js is maintained by [Vercel](https://vercel.com/). You can [deploy a Next.js app](https://nextjs.org/docs/deployment) to any Node.js or serverless hosting, or to your own server. Next.js also supports [static export](https://beta.nextjs.org/docs/configuring/static-export) which doesn't require a server. -Next.js's App Router is **currently in beta and is not yet recommended for production** (as of Mar 2023). To experiment with it in an existing Next.js project, [follow this incremental migration guide](https://beta.nextjs.org/docs/upgrade-guide#migrating-from-pages-to-app). +Маршрутизатор приложения Next.js **находится в бета-разработке и не рекомендуется к использованию в продакшене** (апрель 2023). Если вы хотите поэкспериментировать с новыми возможностями в существующем проекте, [воспользуйтесь руководством по миграции](https://beta.nextjs.org/docs/upgrade-guide#migrating-from-pages-to-app). -#### Which features make up the React team’s full-stack architecture vision? {/*which-features-make-up-the-react-teams-full-stack-architecture-vision*/} +#### Что включает архитектурное видение фулстек-приложений командой React? {/*which-features-make-up-the-react-teams-full-stack-architecture-vision*/} -Next.js's App Router bundler fully implements the official [React Server Components specification](https://github.com/reactjs/rfcs/blob/main/text/0188-server-components.md). This lets you mix build-time, server-only, and interactive components in a single React tree. +Бандлер маршрутизатора приложения Next.js полностью реализует официальную [спецификацию серверных React-компонентов](https://github.com/reactjs/rfcs/blob/main/text/0188-server-components.md). Это даёт возможность сочетать компоненты, сгенерированные во время сборки, на сервере и на клиенте в одном React-дереве. -For example, you can write a server-only React component as an `async` function that reads from a database or from a file. Then you can pass data down from it to your interactive components: +Например, вы можете написать серверный компонент как асинхронную функцию и прочитать данные из базы или файла. После этого вы можете передать эти данные ниже по дереву в динамический компонент, который будет запускаться в браузере: ```js -// This component runs *only* on the server (or during the build). +// Этот компонент запускается *только* на сервере (или во время сборки). async function Talks({ confId }) { - // 1. You're on the server, so you can talk to your data layer. API endpoint not required. + // 1. Это серверный код, вы можете напрямую обратиться к вашей базе данных без запросов к API. const talks = await db.Talks.findAll({ confId }); - // 2. Add any amount of rendering logic. It won't make your JavaScript bundle larger. + // 2. Добавьте любую логику рендеринга. Это не увеличит ваш JavaScript бандл. const videos = talks.map(talk => talk.video); - // 3. Pass the data down to the components that will run in the browser. + // 3. Передайте данные ниже по дереву в компонент, который будет запускаться в браузере. return ; } ``` -Next.js's App Router also integrates [data fetching with Suspense](/blog/2022/03/29/react-v18#suspense-in-data-frameworks). This lets you specify a loading state (like a skeleton placeholder) for different parts of your user interface directly in your React tree: +Маршрутизатор приложения Next.js также поддерживает [загрузку данных с задержкой (Suspense)](/blog/2022/03/29/react-v18#suspense-in-data-frameworks). Так вы можете задать вид различных частей вашего приложения при загрузке (например, показать заглушки) прямо в React-дереве: ```js }> @@ -128,6 +129,6 @@ Next.js's App Router also integrates [data fetching with Suspense](/blog/2022/03 ``` -Server Components and Suspense are React features rather than Next.js features. However, adopting them at the framework level requires buy-in and non-trivial implementation work. At the moment, the Next.js App Router is the most complete implementation. The React team is working with bundler developers to make these features easier to implement in the next generation of frameworks. +Серверные компоненты и задержка -- скорее возможности React, чем Next.js. Однако, команда фреймворка должна подписаться на их внедрение и провести нетривиальную работу. В данный момент маршрутизатор приложения Next.js является наиболее полной реализацией этих возможностей. Команда React продолжает совместную работу с разработчиками бандлеров над предоставлением новых возможностей в следующем поколении фреймворков. diff --git a/src/sidebarLearn.json b/src/sidebarLearn.json index 89d5cffca..3aafad3e4 100644 --- a/src/sidebarLearn.json +++ b/src/sidebarLearn.json @@ -25,7 +25,7 @@ "path": "/learn/installation", "routes": [ { - "title": "Start a New React Project", + "title": "Создаём новый проект с React", "path": "/learn/start-a-new-react-project" }, { @@ -186,7 +186,7 @@ }, { "title": "Removing Effect Dependencies", - "path": "/learn/removing-effect-dependencies" + "path": "/learn/removing-effect-dependencies" }, { "title": "Reusing Logic with Custom Hooks", From b3ba9ba9de3ac2fed5d5d66603394be55422e8a2 Mon Sep 17 00:00:00 2001 From: XamzatJR Date: Wed, 26 Apr 2023 08:40:47 +0300 Subject: [PATCH 039/233] Update Fragment.md --- src/content/reference/react/Fragment.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/content/reference/react/Fragment.md b/src/content/reference/react/Fragment.md index 9926088a3..73bd627b4 100644 --- a/src/content/reference/react/Fragment.md +++ b/src/content/reference/react/Fragment.md @@ -4,7 +4,7 @@ title: (<>...) -``, часто используемый с помощью синтаксиса `<>...`, позволяет группировать элементы без создания оберточного узла. +``, часто используемый с помощью синтаксиса `<>...`, позволяет группировать элементы без оборачивания в дополнительный тег. ```js <> @@ -23,7 +23,7 @@ title: (<>...) ### `` {/*fragment*/} -Оберните элементы в ``, чтобы сгруппировать их вместе в тех случаях, когда вам необходим единственный элемент. Группировка элементов с помощью `Fragment` не влияет на конечный DOM; он остается таким же, как если бы элементы не были сгруппированы. Пустой JSX тег `<>` в большинстве случаев является сокращением для ``. +Оберните элементы в ``, чтобы сгруппировать их вместе в тех случаях, когда вам необходим единственный элемент. Группировка элементов с помощью `Fragment` не влияет на конечный DOM; он остается таким же, как если бы элементы не были сгруппированы. Пустой JSX-тег `<>` в большинстве случаев является сокращением для ``. #### Пропсы {/*props*/} @@ -41,7 +41,7 @@ title: (<>...) ### Возвращение нескольких элементов {/*returning-multiple-elements*/} -Используйте `Fragment` или аналогичный синтаксис `<>...`, чтобы сгруппировать несколько элементов. Вы можете использовать его для размещения нескольких элементов в любом месте, где может находиться один элемент. Например, компонент может возвращать только один элемент, но используя Fragment, вы можете сгруппировать несколько элементов вместе и затем вернуть их как группу: +Используйте `Fragment` или аналогичный синтаксис `<>...`, чтобы сгруппировать несколько элементов. Вы можете использовать его для размещения нескольких элементов в любом месте, где может находиться один элемент. Например, компонент может возвращать только один элемент, но используя `Fragment`, вы можете сгруппировать несколько элементов вместе и затем вернуть их как группу: ```js {3,6} function Post() { @@ -54,7 +54,7 @@ function Post() { } ``` -Фрагменты полезны тем, что группировка элементов с их помощью не влияет на отображение элементов на странице или стили, в отличие от случая, когда вы оборачиваете элементы в другой контейнер, например, в DOM элемент. Если вы осмотрите этот пример с помощью инструментов браузера, то увидите, что все DOM узлы `

    ` и `

    ` отображаются как соседи без оберток вокруг них: +Фрагменты полезны тем, что группировка элементов с их помощью не влияет на отображение элементов на странице или стили, в отличие от случая, когда вы оборачиваете элементы в другой контейнер, например, в DOM-элемент. Если вы проверите этот пример с помощью инструментов браузера, то увидите, что все DOM-узлы `

    ` и `

    ` отображаются как соседи без оберток вокруг них: @@ -111,7 +111,7 @@ function Post() { } ``` -В большинстве случаев это не нужно, за исключением ситуаций, когда необходимо [передать `key` фрагменту.](#rendering-a-list-of-fragments) +В большинстве случаев это не нужно, за исключением ситуаций, когда необходимо [передать фрагменту `key`.](#rendering-a-list-of-fragments) @@ -160,7 +160,7 @@ function DateRangePicker({ start, end }) { ### Рендеринг списка фрагментов {/*rendering-a-list-of-fragments*/} -Рассмотрим ситуацию, когда вам нужно явно написать `Fragment`, вместо использования синтаксиса `<>`. Это может понадобиться, когда вы [рендерите несколько элементов в цикле](/learn/rendering-lists) и каждому элементу нужно присвоить `key`. Если элементы в цикле являются фрагментами, то вам необходимо использовать стандартный синтаксис JSX элементов, чтобы предоставить атрибут `key`: +Рассмотрим ситуацию, когда вам нужно явно написать `Fragment`, вместо использования синтаксиса `<>`. Это может понадобиться, когда вы [рендерите несколько элементов в цикле](/learn/rendering-lists) и каждому элементу нужно присвоить `key`. Если элементы в цикле являются фрагментами, то вам необходимо использовать стандартный синтаксис JSX-элементов, чтобы предоставить атрибут `key`: ```js {3,6} function Blog() { @@ -173,7 +173,7 @@ function Blog() { } ``` -Вы можете осмотреть DOM, чтобы убедиться, что вокруг дочерних элементов фрагмента нет оберток: +Вы можете проверить DOM, чтобы убедиться, что вокруг дочерних элементов фрагмента нет оберток: From 221876d20dd6909ae4481e9fb221e5ed7467716b Mon Sep 17 00:00:00 2001 From: Pavel Zenov Date: Wed, 26 Apr 2023 10:57:22 +0300 Subject: [PATCH 040/233] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Предложения от gcor, самостоятельно замеченные случаи неиспользования буквы `ё` Co-authored-by: Anton Ahatov --- src/content/learn/index.md | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/content/learn/index.md b/src/content/learn/index.md index e7dda8f35..9d1052ba4 100644 --- a/src/content/learn/index.md +++ b/src/content/learn/index.md @@ -4,7 +4,7 @@ title: Quick Start -Добро пожаловать в документацию React! Эта страница посвятит вас в основы 80% концепций React, которыми вы будете пользоваться каждый день. +Добро пожаловать в документацию React! Эта страница познакомит вас с большинством концепций React, которыми вы будете пользоваться каждый день. @@ -13,14 +13,14 @@ title: Quick Start - Как добавлять разметку и стили - Как отображать данные - Как отрисовывать условия и списки -- Как реагировать на события и обновлять экран +- Как реагировать на события и обновлять страницу - Как обмениваться данными между компонентами ## Создание и вложение компонентов {/*components*/} -Приложения на React собираются из *компонентов*. Компонент — это часть пользовательского интерфейса, у которой есть свои логика и внешность. Компоненты в размерах разнятся от мелких кнопок до больших цельных страниц. +Приложения на React собираются из *компонентов*. Компонент — это часть пользовательского интерфейса, у которого есть собственная логика и внешность. Компонент может быть маленьким, как кнопка, или большим, как целая страница. Компоненты React — это функции JavaScript, которые возвращают разметку: @@ -76,7 +76,7 @@ export default function MyApp() { ## Написание разметки с JSX {/*writing-markup-with-jsx*/} -Используемый в примерах выше синтаксис разметки называется *JSX*. Он не обязателен, но большинство проектов на React предпочитают его использовать за удобство. Все [инструменты, которые мы рекомендуем для локальной разработки,](/learn/installation) поддерживают JSX из коробки. +Синтаксис разметки, который вы видели выше, называется *JSX*. Он не обязателен, но большинство проектов на React предпочитают его использовать из-за удобства. Все [инструменты, которые мы рекомендуем для локальной разработки,](/learn/installation) поддерживают JSX. JSX строже HTML. Вам нужно закрывать теги вроде `
    `. Ваш компонент также не может возвращать несколько JSX-тегов. Их нужно будет обернуть внутрь общего родителя, например, `

    ...
    ` или пустую обёртку вида `<>...`: @@ -101,7 +101,7 @@ function AboutPage() { ``` -В отдельном CSS-файле вы прописываете стили для него. +В отдельном CSS-файле вы прописываете для него стили. ```css /* В вашем CSS */ @@ -114,7 +114,7 @@ React не ограничивает вас в том, как добавлять ## Отображение данных {/*displaying-data*/} -JSX позволяет вам встраивать разметку в JavaScript, а фигурные скобки позволяют вам "выйти" в JavaScript для того, чтобы вы могли встроить какую-либо переменную из вашего кода и показать ее пользователю. Например, этот код отобразит переменную `user.name`: +Фигурные скобки внутри JSX-разметки позволяют использовать JavaScript, например для того чтобы отобразить свою переменную пользователю. Код ниже отобразит `user.name`: ```js {3} return ( @@ -124,7 +124,7 @@ return ( ); ``` -Вы тажке можете "выйти в JavaScript" из атрибутов JSX, но вам нужно использовать фигурные скобки *вместо* кавычек. Например, `className="avatar"` передает строку `"avatar"` как класс CSS, но `src={user.imageUrl}` считывает значение JavaScript-переменной `user.imageUrl` и затем передает его в качестве атрибута `src`: +Вы также можете использовать JavaScript в атрибутах JSX. В таком случае вам нужно поставить фигурные скобки *вместо* кавычек. Например, `className="avatar"` передаёт строку `"avatar"` как CSS-класс, а `src={user.imageUrl}` считывает значение JavaScript-переменной `user.imageUrl` и передаёт его в качестве атрибута `src`: ```js {3,4} return ( @@ -135,7 +135,7 @@ return ( ); ``` -Вы также можете прописывать более сложные выражения внутри фигурных скобок JSX, например, [сложение строк](https://learn.javascript.ru/operators#slozhenie-strok-pri-pomoschi-binarnogo): +Вы также можете использовать в JSX более сложные выражения внутри фигурных скобок, например, [сложение строк](https://learn.javascript.ru/operators#slozhenie-strok-pri-pomoschi-binarnogo): @@ -176,11 +176,11 @@ export default function Profile() { -В этом примере `style={{}}` не явлется особым синтаксисом, а представляет из себя обычный объект `{}` внутри фигурных скобок JSX `style={ }`. Вы можете использовать атрибут `style` в случаях, когда ваши стили зависят от переменных JavaScript. +В этом примере `style={{}}` не является специальным синтаксисом, а представляет из себя обычный объект `{}` внутри фигурных скобок JSX `style={ }`. Вы можете использовать атрибут `style` в случаях, когда ваши стили зависят от переменных JavaScript. ## Условный рендеринг {/*conditional-rendering*/} -В React не существует особого синтаксиса для описания условий, вместо этого пишите привычный вам код на JavaScript. Например, для условного использования JSX-кода можно применять инструкцию [`if`](https://developer.mozilla.org/ru-RU/docs/Web/JavaScript/Reference/Statements/if...else): +В React не существует специального синтаксиса для описания условий, вместо этого можно использовать обычный код на JavaScript. Например, для условного рендеринга JSX-кода можно применять [`if`](https://developer.mozilla.org/ru-RU/docs/Web/JavaScript/Reference/Statements/if...else): ```js let content; @@ -216,7 +216,7 @@ return ( ``` -Все эти способы подходят и для условного задания атрибутов. Если вам не знакомы такие синтаксические конструкции JavaScript, вы можете начать с повсеместного использования `if...else`. +Все эти способы подходят и для задания условий в атрибутах. Если вам не знакомы такие синтаксические конструкции JavaScript, вы можете начать с использования `if...else`. ## Рендеринг списков {/*rendering-lists*/} @@ -279,7 +279,7 @@ export default function ShoppingList() { ## Обработка событий {/*responding-to-events*/} -Можно реагировать на события, объявляя внутри ваших компонентов функции *обработчиков событий*: +Вы можете реагировать на события, объявляя внутри ваших компонентов функции *обработчиков событий*: ```js {2-4,7} function MyButton() { @@ -315,9 +315,9 @@ function MyButton() { // ... ``` -`useState` вернет вам две сущности: текущее состояние (`count`) и функцию (`setCount`), которая обновляет его. Можно назвать их как вам угодно, но такого рода вещи принято называть `[something, setSomething]`. +`useState` вернет вам две вещи: текущее состояние (`count`) и функцию (`setCount`), которая обновляет его. Можно именовать их как вам угодно, но такого рода вещи принято называть `[something, setSomething]`. -На первый показ кнопки `count` будет иметь значение `0`, потому что вы передали `0` в `useState()`. Когда вы хотите изменить состояние, вызовите `setCount()` и передайте туда новое значение. Клик на эту кнопку будет увеличивать счётчик: +При первом показе кнопка `count` будет иметь значение `0`, потому что вы передали `0` в `useState()`. Чтобы изменить состояние, вызовите `setCount()` и передайте туда новое значение. Клик на эту кнопку будет увеличивать счётчик: ```js {5} function MyButton() { @@ -422,7 +422,7 @@ button { -При клике `MyApp` обновляет своё состояние `count` значением `1` и передает его вниз обоим потомкам +При клике `MyApp` обновляет своё состояние `count` на значение `1` и передаёт его вниз обоим потомкам @@ -532,6 +532,6 @@ button { ## Следующие шаги {/*next-steps*/} -Теперь вы знаете, как писать простой код для React! +Теперь вы знаете основы, как писать код для React! -Ознакомьтесь с [введением](/learn/tutorial-tic-tac-toe), в рамках которого вы примените полученные знания и соберёте свое первое мини-приложение на React. +Ознакомьтесь с [введением](/learn/tutorial-tic-tac-toe), в рамках которого вы сможете применить полученные знания и собрать своё первое мини-приложение на React. From 03f0947fd4326bd959881be1a4ad124b24ede035 Mon Sep 17 00:00:00 2001 From: Palidos <36964844+Palidos@users.noreply.github.com> Date: Wed, 26 Apr 2023 15:43:54 +0300 Subject: [PATCH 041/233] Add review suggestions --- src/content/learn/installation.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/content/learn/installation.md b/src/content/learn/installation.md index ef8e56322..13a86103d 100644 --- a/src/content/learn/installation.md +++ b/src/content/learn/installation.md @@ -4,15 +4,15 @@ title: Установка -React изначально был спроектирован так, чтобы его можно было внедрять постепенно. Другими словами, вы можете начать с малого и использовать только ту функциональность React, которая необходима вам в данный момент. Информация в этом разделе будет полезна в любой ситуации: при первом знакомстве с React, при создании простой динамической HTML-страницы и даже при проектировании сложного React-приложения. +React был спроектирован так, чтобы его можно было внедрять постепенно. Вы можете начать с малого и использовать только ту функциональность React, которая необходима вам в данный момент. Информация в этом разделе будет полезна как при первом знакомстве с React, так и при создании простой динамической HTML-страницы или проектировании сложного React-приложения. -* [Как создать новый React проект](/learn/start-a-new-react-project) -* [Как добавить React в уже существующий проект](/learn/add-react-to-an-existing-project) +* [Как создать новый проект на React](/learn/start-a-new-react-project) +* [Как добавить React в существующий проект](/learn/add-react-to-an-existing-project) * [Как настроить редактор кода](/learn/editor-setup) * [Как установить React Developer Tools](/learn/react-developer-tools) @@ -38,19 +38,19 @@ export default function App() { Вы можете редактировать прямо здесь или же открыть код в новой вкладке, нажав на кнопку "Форкнуть" в правом верхнем углу. -Такие песочницы есть на большинстве страниц React документации. За пределами React документации также есть большое количество песочниц, поддерживающих React. Например: [CodeSandbox](https://codesandbox.io/s/new), [StackBlitz](https://stackblitz.com/fork/react) или [CodePen.](https://codepen.io/pen?&editors=0010&layout=left&prefill_data_id=3f4569d1-1b11-4bce-bd46-89090eed5ddb) +Такие песочницы есть на большинстве страниц React-документации. За пределами React-документации также есть большое количество песочниц, поддерживающих React. Например: [CodeSandbox](https://codesandbox.io/s/new), [StackBlitz](https://stackblitz.com/fork/react) или [CodePen.](https://codepen.io/pen?&editors=0010&layout=left&prefill_data_id=3f4569d1-1b11-4bce-bd46-89090eed5ddb) ### Поиграть с React локально {/*try-react-locally*/} Что бы поиграть с React локально на вашем компьютере, [скачайте эту HTML страницу.](https://gist.githubusercontent.com/gaearon/0275b1e1518599bbeafcde4722e79ed1/raw/db72dcbf3384ee1708c4a07d3be79860db04bff0/example.html) Откройте ее в своем текстовом редакторе и браузере! -## Начать новый React проект {/*start-a-new-react-project*/} +## Начать новый проект на React {/*start-a-new-react-project*/} -Если вы хотите создать приложение или сайт полностью на React — [создайте новый React проект.](/learn/start-a-new-react-project) +Если вы хотите создать приложение или сайт полностью на React — [создайте новый проект на React.](/learn/start-a-new-react-project) -## Добавить React в уже существующий проект {/*add-react-to-an-existing-project*/} +## Добавить React в существующий проект {/*add-react-to-an-existing-project*/} -Если вы хотите использовать React в уже существующем приложении или сайте — [добавьте React в уже существующий проект.](/learn/add-react-to-an-existing-project) +Если вы хотите использовать React в существующем приложении или сайте — [добавьте React в существующий проект.](/learn/add-react-to-an-existing-project) ## Дальнейшие шаги {/*next-steps*/} From a2ef01156b6599aaa7ae3348fee362a4b6cc9e12 Mon Sep 17 00:00:00 2001 From: Palidos <36964844+Palidos@users.noreply.github.com> Date: Wed, 26 Apr 2023 16:08:51 +0300 Subject: [PATCH 042/233] Fix line break Fix "Start a New React Project" translation --- src/content/learn/installation.md | 108 +++++++++++++++--------------- 1 file changed, 54 insertions(+), 54 deletions(-) diff --git a/src/content/learn/installation.md b/src/content/learn/installation.md index 13a86103d..f650d065f 100644 --- a/src/content/learn/installation.md +++ b/src/content/learn/installation.md @@ -1,58 +1,58 @@ ---- -title: Установка ---- - - - -React был спроектирован так, чтобы его можно было внедрять постепенно. Вы можете начать с малого и использовать только ту функциональность React, которая необходима вам в данный момент. Информация в этом разделе будет полезна как при первом знакомстве с React, так и при создании простой динамической HTML-страницы или проектировании сложного React-приложения. - - - - - - -* [Как создать новый проект на React](/learn/start-a-new-react-project) -* [Как добавить React в существующий проект](/learn/add-react-to-an-existing-project) -* [Как настроить редактор кода](/learn/editor-setup) -* [Как установить React Developer Tools](/learn/react-developer-tools) - - - +--- +title: Установка +--- + + + +React был спроектирован так, чтобы его можно было внедрять постепенно. Вы можете начать с малого и использовать только ту функциональность React, которая необходима вам в данный момент. Информация в этом разделе будет полезна как при первом знакомстве с React, так и при создании простой динамической HTML-страницы или проектировании сложного React-приложения. + + + + + + +* [Как создать новый React-проект](/learn/start-a-new-react-project) +* [Как добавить React в существующий проект](/learn/add-react-to-an-existing-project) +* [Как настроить редактор кода](/learn/editor-setup) +* [Как установить React Developer Tools](/learn/react-developer-tools) + + + ## Пробуем React {/*try-react*/} - -Чтобы попробовать React, даже устанавливать ничего не нужно. Редактируйте прямо в песочнице! - - - -```js -function Greeting({ name }) { - return

    Hello, {name}

    ; -} - -export default function App() { - return -} -``` - -
    - -Вы можете редактировать прямо здесь или же открыть код в новой вкладке, нажав на кнопку "Форкнуть" в правом верхнем углу. - -Такие песочницы есть на большинстве страниц React-документации. За пределами React-документации также есть большое количество песочниц, поддерживающих React. Например: [CodeSandbox](https://codesandbox.io/s/new), [StackBlitz](https://stackblitz.com/fork/react) или [CodePen.](https://codepen.io/pen?&editors=0010&layout=left&prefill_data_id=3f4569d1-1b11-4bce-bd46-89090eed5ddb) - + +Чтобы попробовать React, даже устанавливать ничего не нужно. Редактируйте прямо в песочнице! + + + +```js +function Greeting({ name }) { + return

    Hello, {name}

    ; +} + +export default function App() { + return +} +``` + +
    + +Вы можете редактировать прямо здесь или же открыть код в новой вкладке, нажав на кнопку "Форкнуть" в правом верхнем углу. + +Такие песочницы есть на большинстве страниц React-документации. За пределами React-документации также есть большое количество песочниц, поддерживающих React. Например: [CodeSandbox](https://codesandbox.io/s/new), [StackBlitz](https://stackblitz.com/fork/react) или [CodePen.](https://codepen.io/pen?&editors=0010&layout=left&prefill_data_id=3f4569d1-1b11-4bce-bd46-89090eed5ddb) + ### Поиграть с React локально {/*try-react-locally*/} - -Что бы поиграть с React локально на вашем компьютере, [скачайте эту HTML страницу.](https://gist.githubusercontent.com/gaearon/0275b1e1518599bbeafcde4722e79ed1/raw/db72dcbf3384ee1708c4a07d3be79860db04bff0/example.html) Откройте ее в своем текстовом редакторе и браузере! - -## Начать новый проект на React {/*start-a-new-react-project*/} - -Если вы хотите создать приложение или сайт полностью на React — [создайте новый проект на React.](/learn/start-a-new-react-project) - + +Что бы поиграть с React локально на вашем компьютере, [скачайте эту HTML страницу.](https://gist.githubusercontent.com/gaearon/0275b1e1518599bbeafcde4722e79ed1/raw/db72dcbf3384ee1708c4a07d3be79860db04bff0/example.html) Откройте ее в своем текстовом редакторе и браузере! + +## Начать новый React-проект {/*start-a-new-react-project*/} + +Если вы хотите создать приложение или сайт полностью на React — [создайте новый React-проект.](/learn/start-a-new-react-project) + ## Добавить React в существующий проект {/*add-react-to-an-existing-project*/} - -Если вы хотите использовать React в существующем приложении или сайте — [добавьте React в существующий проект.](/learn/add-react-to-an-existing-project) - + +Если вы хотите использовать React в существующем приложении или сайте — [добавьте React в существующий проект.](/learn/add-react-to-an-existing-project) + ## Дальнейшие шаги {/*next-steps*/} - -Перейдите к [Введению в React](/learn) для ознакомления с самыми важными его концепциями. - + +Перейдите к [Введению в React](/learn) для ознакомления с самыми важными его концепциями. + From 5dd5d4dfe1b7c937af6966518c6144a1a84b5b91 Mon Sep 17 00:00:00 2001 From: Palidos <36964844+Palidos@users.noreply.github.com> Date: Wed, 26 Apr 2023 16:11:22 +0300 Subject: [PATCH 043/233] Delete extra line --- src/content/learn/installation.md | 1 - 1 file changed, 1 deletion(-) diff --git a/src/content/learn/installation.md b/src/content/learn/installation.md index f650d065f..6c8fca184 100644 --- a/src/content/learn/installation.md +++ b/src/content/learn/installation.md @@ -6,7 +6,6 @@ title: Установка React был спроектирован так, чтобы его можно было внедрять постепенно. Вы можете начать с малого и использовать только ту функциональность React, которая необходима вам в данный момент. Информация в этом разделе будет полезна как при первом знакомстве с React, так и при создании простой динамической HTML-страницы или проектировании сложного React-приложения. - From 008577aade6f304f91c8c2f7ddb0d20cfca857c2 Mon Sep 17 00:00:00 2001 From: Konstantin Arabei Date: Wed, 26 Apr 2023 23:27:11 +0700 Subject: [PATCH 044/233] Translate You First Component page --- src/components/MDX/Challenges/Challenge.tsx | 8 +- src/components/MDX/ExpandableCallout.tsx | 2 +- src/components/MDX/ExpandableExample.tsx | 2 +- src/components/MDX/MDXComponents.tsx | 2 +- src/components/MDX/Recap.tsx | 2 +- src/content/learn/your-first-component.md | 185 ++++++++++---------- 6 files changed, 100 insertions(+), 101 deletions(-) diff --git a/src/components/MDX/Challenges/Challenge.tsx b/src/components/MDX/Challenges/Challenge.tsx index 24e99541c..b66d5a99b 100644 --- a/src/components/MDX/Challenges/Challenge.tsx +++ b/src/components/MDX/Challenges/Challenge.tsx @@ -63,14 +63,14 @@ export function Challenge({
    ) : ( @@ -80,7 +80,7 @@ export function Challenge({ onClick={toggleSolution} active={showSolution}> {' '} - {showSolution ? 'Hide solution' : 'Show solution'} + {showSolution ? 'Скрыть решение' : 'Показать решение'} ) )} @@ -109,7 +109,7 @@ export function Challenge({ {currentChallenge.solution}
    {hasNextChallenge && (
    {children}; } diff --git a/src/components/MDX/Recap.tsx b/src/components/MDX/Recap.tsx index d91ed48b4..f37c85f17 100644 --- a/src/components/MDX/Recap.tsx +++ b/src/components/MDX/Recap.tsx @@ -13,7 +13,7 @@ function Recap({children}: RecapProps) { return (

    - Recap + Итого

    {children}
    diff --git a/src/content/learn/your-first-component.md b/src/content/learn/your-first-component.md index 343823aa4..4d1ac2efd 100644 --- a/src/content/learn/your-first-component.md +++ b/src/content/learn/your-first-component.md @@ -1,47 +1,47 @@ --- -title: Your First Component +title: Ваш первый компонент --- -*Components* are one of the core concepts of React. They are the foundation upon which you build user interfaces (UI), which makes them the perfect place to start your React journey! +*Компоненты* — это один из основных концептов React. Они являются основой, на которой вы строите пользовательские интерфейсы (UI), что делает их идеальным местом для начала вашего пути в React! -* What a component is -* What role components play in a React application -* How to write your first React component +* Что такое компонент +* Какую роль играют компоненты в React приложении +* Как написать ваш первый React компонент -## Components: UI building blocks {/*components-ui-building-blocks*/} +## Компоненты: строительные блоки UI {/*components-ui-building-blocks*/} -On the Web, HTML lets us create rich structured documents with its built-in set of tags like `

    ` and `
  • `: +В Интернете, HTML позволяет нам создавать структурированные документы с использованием встроенного набора тегов, таких как `

    ` и `
  • `: ```html
    -

    My First Component

    +

    Мой Первый Компонент

      -
    1. Components: UI Building Blocks
    2. -
    3. Defining a Component
    4. -
    5. Using a Component
    6. +
    7. Компоненты: Cтроительные Блоки UI
    8. +
    9. Определение Компонента
    10. +
    11. Использование Компонента
    ``` -This markup represents this article `
    `, its heading `

    `, and an (abbreviated) table of contents as an ordered list `
      `. Markup like this, combined with CSS for style, and JavaScript for interactivity, lies behind every sidebar, avatar, modal, dropdown—every piece of UI you see on the Web. +Эта разметка представляет эту статью как `
      `, её заголовок как `

      ` и (сокращённое) оглавление как упорядоченный список `
        `. Такая разметка, в сочетании с CSS для стилизации и JavaScript для создания интерактивности, лежит в основе каждой боковой панели, аватара, модального окна, выпадающего меню — каждой части UI, которую вы видите в Интернете. -React lets you combine your markup, CSS, and JavaScript into custom "components", **reusable UI elements for your app.** The table of contents code you saw above could be turned into a `` component you could render on every page. Under the hood, it still uses the same HTML tags like `
        `, `

        `, etc. +React позволяет вам объединять разметку, CSS и JavaScript в пользовательские "компоненты", **переиспользуемые элементы UI для вашего приложения**. Код оглавления, который вы видели выше, можно превратить в компонент ``, который можно отрендерить на каждой странице. Внутри он всё ещё использует те же HTML-теги, такие как `
        `, `

        ` и т.д. -Just like with HTML tags, you can compose, order and nest components to design whole pages. For example, the documentation page you're reading is made out of React components: +Как и с HTML-тегами, вы можете комбинировать, упорядочивать и вкладывать компоненты для создания целых страниц. Например, страница документации, которую вы сейчас читаете, состоит из React компонентов: ```js - Docs + Документы @@ -51,11 +51,11 @@ Just like with HTML tags, you can compose, order and nest components to design w ``` -As your project grows, you will notice that many of your designs can be composed by reusing components you already wrote, speeding up your development. Our table of contents above could be added to any screen with ``! You can even jumpstart your project with the thousands of components shared by the React open source community like [Chakra UI](https://chakra-ui.com/) and [Material UI.](https://material-ui.com/) +По мере роста вашего проекта вы заметите, что многие из ваших дизайнов могут быть составлены с помощью переиспользования уже написанных вами компонентов, ускоряя вашу разработку. Наше оглавление выше может быть добавлено на любой экран с помощью ``! Вы также можете начать свой проект, используя тысячи компонентов с открытым исходным кодом, которые были созданы React-сообществом, например [Chakra UI](https://chakra-ui.com/) и [Material UI.](https://material-ui.com/) -## Defining a component {/*defining-a-component*/} +## Определение компонента {/*defining-a-component*/} -Traditionally when creating web pages, web developers marked up their content and then added interaction by sprinkling on some JavaScript. This worked great when interaction was a nice-to-have on the web. Now it is expected for many sites and all apps. React puts interactivity first while still using the same technology: **a React component is a JavaScript function that you can _sprinkle with markup_.** Here's what that looks like (you can edit the example below): +Традиционно при создании веб-страниц разработчики размечали свой контент, а затем добавляли немного интерактивности с помощью JavaScript. Это работало отлично, когда интерактивность была просто дополнительным элементом в Интернете. Сегодня она стала обязательной для многих сайтов и всех приложений. React ставит взаимодействие на первое место, при этом используя ту же технологию: **компонент React представляет собой JavaScript-функцию, которую можно _припудрить разметкой_.** Вот как это выглядит (вы можете отредактировать пример ниже): @@ -64,7 +64,7 @@ export default function Profile() { return ( Katherine Johnson ) } @@ -76,51 +76,50 @@ img { height: 200px; } -And here's how to build a component: +А вот как создать компонент: -### Step 1: Export the component {/*step-1-export-the-component*/} +### Шаг 1: Экспортировать компонент {/*step-1-export-the-component*/} -The `export default` prefix is a [standard JavaScript syntax](https://developer.mozilla.org/docs/web/javascript/reference/statements/export) (not specific to React). It lets you mark the main function in a file so that you can later import it from other files. (More on importing in [Importing and Exporting Components](/learn/importing-and-exporting-components)!) +Префикс `export default` — это [стандартный синтаксис JavaScript](https://developer.mozilla.org/ru/docs/web/javascript/reference/statements/export) (не является спецификой React). Он позволяет пометить основную функцию в файле, чтобы её можно было импортировать из других файлов. (Подробее об импорте в [Импорт и Экспорт компонентов](/learn/importing-and-exporting-components)!) +### Шаг 2: Определить функцию {/*step-2-define-the-function*/} -### Step 2: Define the function {/*step-2-define-the-function*/} - -With `function Profile() { }` you define a JavaScript function with the name `Profile`. +С помощью `function Profile() { }` вы определяете JavaScript-функцию с именем `Profile`. -React components are regular JavaScript functions, but **their names must start with a capital letter** or they won't work! +React компоненты — это обычные фукнции JavaScript, но **их имена должны начинаться с заглавной буквы**, иначе они не будут работать! -### Step 3: Add markup {/*step-3-add-markup*/} +### Шаг 3: Добавить разметку {/*step-3-add-markup*/} -The component returns an `` tag with `src` and `alt` attributes. `` is written like HTML, but it is actually JavaScript under the hood! This syntax is called [JSX](/learn/writing-markup-with-jsx), and it lets you embed markup inside JavaScript. +Компонент возвращает тег `` с атрибутами `src` и `alt`. `` выглядит как HTML, но на самом деле это JavaScript! Этот синтаксис называется [JSX](/learn/writing-markup-with-jsx), и он позволяет вам вставлять разметку внутрь JavaScript. -Return statements can be written all on one line, as in this component: +Оператор `return` можно записать в одну строку, как в этом компоненте: ```js -return Katherine Johnson; +return Кэтрин Джонсон; ``` -But if your markup isn't all on the same line as the `return` keyword, you must wrap it in a pair of parentheses: +Но если вся ваша разметка не находится на той же строке, что и ключевое слово `return`, вы должны обернуть её в пару скобок: ```js return (
        - Katherine Johnson + Кэтрин Джонсон
        ); ``` -Without parentheses, any code on the lines after `return` [will be ignored](https://stackoverflow.com/questions/2846283/what-are-the-rules-for-javascripts-automatic-semicolon-insertion-asi)! +Без скобок любой код на строках после `return` [будет проигнорирован](https://stackoverflow.com/questions/2846283/what-are-the-rules-for-javascripts-automatic-semicolon-insertion-asi)! -## Using a component {/*using-a-component*/} +## Использование компонента {/*using-a-component*/} -Now that you've defined your `Profile` component, you can nest it inside other components. For example, you can export a `Gallery` component that uses multiple `Profile` components: +Теперь, когда вы определили компонент `Profile`, вы можете вкладывать его в другие компоненты. Например, вы можете экспортировать компонент `Gallery`, который использует несколько компонентов `Profile`: @@ -129,7 +128,7 @@ function Profile() { return ( Katherine Johnson ); } @@ -137,7 +136,7 @@ function Profile() { export default function Gallery() { return (
        -

        Amazing scientists

        +

        Изумительные учёные

        @@ -152,37 +151,37 @@ img { margin: 0 10px 10px 0; height: 90px; } -### What the browser sees {/*what-the-browser-sees*/} +### Что видит барузер {/*what-the-browser-sees*/} -Notice the difference in casing: +Обратите внимание на разницу в регистре: -* `
        ` is lowercase, so React knows we refer to an HTML tag. -* `` starts with a capital `P`, so React knows that we want to use our component called `Profile`. +* `
        ` в нижнем регистре, поэтому React знает, что мы обращаемся к тегу HTML. +* `` начинается с заглавной буквы `P`, поэтому React знает, что мы хотим использовать наш компонент с именем `Profile`. -And `Profile` contains even more HTML: ``. In the end, this is what the browser sees: +А `Profile` содержит ещё больше HTML: ``. В конечном итоге, вот что видит браузер: ```html
        -

        Amazing scientists

        - Katherine Johnson - Katherine Johnson - Katherine Johnson +

        Изумительные учёные

        + Кэтрин Джонсон + Кэтрин Джонсон + Кэтрин Джонсон
        ``` -### Nesting and organizing components {/*nesting-and-organizing-components*/} +### Вкладывание и организация компонентов {/*nesting-and-organizing-components*/} -Components are regular JavaScript functions, so you can keep multiple components in the same file. This is convenient when components are relatively small or tightly related to each other. If this file gets crowded, you can always move `Profile` to a separate file. You will learn how to do this shortly on the [page about imports.](/learn/importing-and-exporting-components) +Компоненты — это обычные функции JavaScript, поэтому вы можете держать несколько компонентов в одном файле. Это удобно, когда компоненты относительно небольшие или тесно связаны друг с другом. Если этот файл становится переполненным, вы всегда можете переместить `Profile` в отдельный файл. В скором времени вы узнаете, как это сделать на [странице об импортах.](/learn/importing-and-exporting-components) -Because the `Profile` components are rendered inside `Gallery`—even several times!—we can say that `Gallery` is a **parent component,** rendering each `Profile` as a "child". This is part of the magic of React: you can define a component once, and then use it in as many places and as many times as you like. +Поскольку компоненты `Profile` рендерятся внутри компонента `Gallery`—даже несколько раз!—мы можем сказать, что `Gallery` является **родительским компонентом**, который рендерит каждый `Profile` как "ребёнка". Это часть магии React: вы можете определить компонент один раз и затем использовать его в любом количестве мест и сколько угодно раз. -Components can render other components, but **you must never nest their definitions:** +Компоненты могут рендерить другие компоненты, но **вы никогда не должны вкладывать их определения:** ```js {2-5} export default function Gallery() { - // 🔴 Never define a component inside another component! + // 🔴 Никогда не определяйте компонент внутри другого компонента! function Profile() { // ... } @@ -190,47 +189,47 @@ export default function Gallery() { } ``` -The snippet above is [very slow and causes bugs.](/learn/preserving-and-resetting-state#different-components-at-the-same-position-reset-state) Instead, define every component at the top level: +Код выше [очень медленный и вызывает ошибки.](/learn/preserving-and-resetting-state#different-components-at-the-same-position-reset-state) Вместо этого определяйте каждый компонент на верхнем уровне: ```js {5-8} export default function Gallery() { // ... } -// ✅ Declare components at the top level +// ✅ Определяйте компоненты на верхнем уровне function Profile() { // ... } ``` -When a child component needs some data from a parent, [pass it by props](/learn/passing-props-to-a-component) instead of nesting definitions. +Если дочернему компоненту нужны данные от родительского, [передавайте их через пропсы](/learn/passing-props-to-a-component), вместо вложенных определений. -#### Components all the way down {/*components-all-the-way-down*/} +#### Компоненты на все случаи жизни {/*components-all-the-way-down*/} -Your React application begins at a "root" component. Usually, it is created automatically when you start a new project. For example, if you use [CodeSandbox](https://codesandbox.io/) or [Create React App](https://create-react-app.dev/), the root component is defined in `src/App.js`. If you use the framework [Next.js](https://nextjs.org/), the root component is defined in `pages/index.js`. In these examples, you've been exporting root components. +Ваше React-приложение начинается с "корневого" компонента. Обычно он создаётся автоматически при создании нового проекта. Например, если вы используете [CodeSandbox](https://codesandbox.io/) или [Create React App](https://create-react-app.dev/), корневой компонент определён в файле `src/App.js`. Если вы используете фреймворк [Next.js](https://nextjs.org/), корневой компонент определён в файле `pages/index.js`. В этих примерах вы экспортировали корневые компоненты. -Most React apps use components all the way down. This means that you won't only use components for reusable pieces like buttons, but also for larger pieces like sidebars, lists, and ultimately, complete pages! Components are a handy way to organize UI code and markup, even if some of them are only used once. +Большинство React-приложений используют компоненты повсюду. Это означает, что вы будете использовать компоненты не только для переиспользуемых элементов, таких как кнопки, но также для более крупных элементов: боковых панелей, списков и в конечном итоге, целых страниц! Компоненты — это удобный способ организации кода UI и разметки, даже если некоторые из них используются только один раз. -[React-based frameworks](/learn/start-a-new-react-project) take this a step further. Instead of using an empty HTML file and letting React "take over" managing the page with JavaScript, they *also* generate the HTML automatically from your React components. This allows your app to show some content before the JavaScript code loads. +[Фреймворки на основе React](/learn/start-a-new-react-project) пошли ещё дальше. Вместо того, чтобы использовать пустой файл HTML и позволять React "захватывать" управление страницей с помощью JavaScript, они *также* автоматически генерируют HTML из ваших React-компонентов. Это позволяет вашему приложению показывать часть контента до того, как загрузится JavaScript код. -Still, many websites only use React to [add interactivity to existing HTML pages.](/learn/add-react-to-an-existing-project#using-react-for-a-part-of-your-existing-page) They have many root components instead of a single one for the entire page. You can use as much—or as little—React as you need. +Тем не менее, многие веб-сайты используют React только для [добавления интерактивности на существующие HTML-страницы.](/learn/add-react-to-an-existing-project#using-react-for-a-part-of-your-existing-page) У них есть множество корневых компонентов вместо одного для всей страницы. Вы можете использовать столько функциональности React, сколько вам нужно. -You've just gotten your first taste of React! Let's recap some key points. - -* React lets you create components, **reusable UI elements for your app.** -* In a React app, every piece of UI is a component. -* React components are regular JavaScript functions except: +Вы только что познакомились с React! Давайте вспомним некоторые ключевые моменты. - 1. Their names always begin with a capital letter. - 2. They return JSX markup. +* React позволяет вам создавать компоненты, **переиспользуемые элементы UI для вашего приложения.** +* В React-приложении каждый элемент UI является компонентом. +* Компоненты React — это обычные функции JavaScript, за исключением того, что: + + 1. Их имена всегда начинаются с заглавной буквы. + 2. Они возвращают разметку JSX. @@ -238,9 +237,9 @@ You've just gotten your first taste of React! Let's recap some key points. -#### Export the component {/*export-the-component*/} +#### Экспортируйте компонент {/*export-the-component*/} -This sandbox doesn't work because the root component is not exported: +Этот пример не работает из-за того, что корневой компонент не экспортирован: @@ -249,7 +248,7 @@ function Profile() { return ( Aklilu Lemma ); } @@ -261,11 +260,11 @@ img { height: 181px; } -Try to fix it yourself before looking at the solution! +Попробуйте исправить его самостоятельно прежде чем смотреть в решение! -Add `export default` before the function definition like so: +Добавьте `export default` перед определением функции, вот так: @@ -274,7 +273,7 @@ export default function Profile() { return ( Aklilu Lemma ); } @@ -286,17 +285,17 @@ img { height: 181px; } -You might be wondering why writing `export` alone is not enough to fix this example. You can learn the difference between `export` and `export default` in [Importing and Exporting Components.](/learn/importing-and-exporting-components) +Возможно, вы задаётесь вопросом, почему написание только `export` недостаточно для исправления этого примера. Вы можете узнать разницу между `export` и `export default` в разделе [Импорт и Экспорт компонентов.](/learn/importing-and-exporting-components) -#### Fix the return statement {/*fix-the-return-statement*/} +#### Исправьте возвращаемое выражение {/*fix-the-return-statement*/} -Something isn't right about this `return` statement. Can you fix it? +Что-то не так с оператором `return`. Вы можете это исправить? -You may get an "Unexpected token" error while trying to fix this. In that case, check that the semicolon appears *after* the closing parenthesis. Leaving a semicolon inside `return ( )` will cause an error. +При попытке исправить это вы можете получить ошибку "Unexpected token". В этом случае убедитесь, что точка с запятой находится *после* закрывающей скобки. Оставление точки с запятой внутри `return ( )` приведёт к ошибке. @@ -306,7 +305,7 @@ You may get an "Unexpected token" error while trying to fix this. In that case, ```js export default function Profile() { return - Katsuko Saruhashi; + Кацуко Сарухаси; } ``` @@ -318,13 +317,13 @@ img { height: 180px; } -You can fix this component by moving the return statement to one line like so: +Вы можете исправить этот компонент, записав возвращаемое выражение в одну строку, например так: ```js export default function Profile() { - return Katsuko Saruhashi; + return Кацуко Сарухаси; } ``` @@ -334,7 +333,7 @@ img { height: 180px; } -Or by wrapping the returned JSX markup in parentheses that open right after `return`: +Или обернув возвращаемуе JSX разметку в скобки, которые открываются сразу после `return`: @@ -343,7 +342,7 @@ export default function Profile() { return ( Katsuko Saruhashi ); } @@ -357,9 +356,9 @@ img { height: 180px; } -#### Spot the mistake {/*spot-the-mistake*/} +#### Найти ошибку {/*spot-the-mistake*/} -Something's wrong with how the `Profile` component is declared and used. Can you spot the mistake? (Try to remember how React distinguishes components from the regular HTML tags!) +Что-то не так с объявлением и использованием компонента `Profile`. Можете найти ошибку? (Попробуйте вспомнить, как React отличает компоненты от обычных тегов HTML!) @@ -368,7 +367,7 @@ function profile() { return ( Alan L. Hart ); } @@ -376,7 +375,7 @@ function profile() { export default function Gallery() { return (
        -

        Amazing scientists

        +

        Изумительные учёные

        @@ -393,9 +392,9 @@ img { margin: 0 10px 10px 0; height: 90px; } -React component names must start with a capital letter. +Имена React-компонентов должны начинаться с заглавной буквы. -Change `function profile()` to `function Profile()`, and then change every `` to ``: +Измените `function profile()` на `function Profile()`, а затем измените каждый `` на ``: @@ -404,7 +403,7 @@ function Profile() { return ( Alan L. Hart ); } @@ -412,7 +411,7 @@ function Profile() { export default function Gallery() { return (
        -

        Amazing scientists

        +

        Изумительные учёные

        @@ -429,14 +428,14 @@ img { margin: 0 10px 10px 0; } -#### Your own component {/*your-own-component*/} +#### Ваш компонент {/*your-own-component*/} -Write a component from scratch. You can give it any valid name and return any markup. If you're out of ideas, you can write a `Congratulations` component that shows `

        Good job!

        `. Don't forget to export it! +Напишите компонент с нуля. Вы можете дать ему любое допустимое имя и возвращать любую разметку. Если ничего не приходит на ум, то вы можете написать компонент `Congratulations`, который отображает `

        Хорошая работа!

        `. Не забудьте экспортировать компонент! ```js -// Write your component below! +// Напишите свой компонент ниже! ``` @@ -449,7 +448,7 @@ Write a component from scratch. You can give it any valid name and return any ma ```js export default function Congratulations() { return ( -

        Good job!

        +

        Хорошая работа!

        ); } ``` From 082cbdf291daef3b7335e134c6dbaeef1db0a949 Mon Sep 17 00:00:00 2001 From: Fedya Petrakov Date: Wed, 26 Apr 2023 19:55:20 +0300 Subject: [PATCH 045/233] Update src/content/reference/react/components.md Co-authored-by: Anton Ahatov --- src/content/reference/react/components.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/reference/react/components.md b/src/content/reference/react/components.md index dac1b4021..0c35127ee 100644 --- a/src/content/reference/react/components.md +++ b/src/content/reference/react/components.md @@ -21,4 +21,4 @@ title: "Встроенные реакт-компоненты" ## Ваши компоненты {/*your-own-components*/} -Вы также можете [создавать свои компоненты](/learn/your-first-component), используя JavaScript функции. +Вы также можете [создавать свои компоненты](/learn/your-first-component), используя JavaScript-функции. From 7c1202d6e8ae64fe435c80a9af4aeb27c04961ae Mon Sep 17 00:00:00 2001 From: Fedya Petrakov Date: Wed, 26 Apr 2023 19:57:59 +0300 Subject: [PATCH 046/233] Update src/content/reference/react/components.md Co-authored-by: Anton Ahatov --- src/content/reference/react/components.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/reference/react/components.md b/src/content/reference/react/components.md index 0c35127ee..8e67e1e27 100644 --- a/src/content/reference/react/components.md +++ b/src/content/reference/react/components.md @@ -1,5 +1,5 @@ --- -title: "Встроенные реакт-компоненты" +title: "Встроенные react-компоненты" --- From d7f98789039a3a33a8833564d57c52c8dae05e3e Mon Sep 17 00:00:00 2001 From: Konstantin Arabei Date: Thu, 27 Apr 2023 00:04:33 +0700 Subject: [PATCH 047/233] minor fixes --- src/content/learn/your-first-component.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/content/learn/your-first-component.md b/src/content/learn/your-first-component.md index 4d1ac2efd..8fdcc0901 100644 --- a/src/content/learn/your-first-component.md +++ b/src/content/learn/your-first-component.md @@ -11,8 +11,8 @@ title: Ваш первый компонент * Что такое компонент -* Какую роль играют компоненты в React приложении -* Как написать ваш первый React компонент +* Какую роль играют компоненты в React-приложении +* Как написать ваш первый React-компонент @@ -35,7 +35,7 @@ title: Ваш первый компонент React позволяет вам объединять разметку, CSS и JavaScript в пользовательские "компоненты", **переиспользуемые элементы UI для вашего приложения**. Код оглавления, который вы видели выше, можно превратить в компонент ``, который можно отрендерить на каждой странице. Внутри он всё ещё использует те же HTML-теги, такие как `
        `, `

        ` и т.д. -Как и с HTML-тегами, вы можете комбинировать, упорядочивать и вкладывать компоненты для создания целых страниц. Например, страница документации, которую вы сейчас читаете, состоит из React компонентов: +Как и с HTML-тегами, вы можете комбинировать, упорядочивать и вкладывать компоненты для создания целых страниц. Например, страница документации, которую вы сейчас читаете, состоит из React-компонентов: ```js @@ -80,14 +80,14 @@ img { height: 200px; } ### Шаг 1: Экспортировать компонент {/*step-1-export-the-component*/} -Префикс `export default` — это [стандартный синтаксис JavaScript](https://developer.mozilla.org/ru/docs/web/javascript/reference/statements/export) (не является спецификой React). Он позволяет пометить основную функцию в файле, чтобы её можно было импортировать из других файлов. (Подробее об импорте в [Импорт и Экспорт компонентов](/learn/importing-and-exporting-components)!) +Префикс `export default` — это [стандартный синтаксис JavaScript](https://developer.mozilla.org/ru/docs/web/javascript/reference/statements/export) (не является спецификой React). Он позволяет пометить основную функцию в файле, чтобы её можно было импортировать из других файлов. (Подробнее об импорте в [Импорт и Экспорт компонентов](/learn/importing-and-exporting-components)!) ### Шаг 2: Определить функцию {/*step-2-define-the-function*/} С помощью `function Profile() { }` вы определяете JavaScript-функцию с именем `Profile`. -React компоненты — это обычные фукнции JavaScript, но **их имена должны начинаться с заглавной буквы**, иначе они не будут работать! +React-компоненты — это обычные фукнции JavaScript, но **их имена должны начинаться с заглавной буквы**, иначе они не будут работать! @@ -155,7 +155,7 @@ img { margin: 0 10px 10px 0; height: 90px; } Обратите внимание на разницу в регистре: -* `
        ` в нижнем регистре, поэтому React знает, что мы обращаемся к тегу HTML. +* `
        ` в нижнем регистре, поэтому React знает, что мы обращаемся к HTML-тегу. * `` начинается с заглавной буквы `P`, поэтому React знает, что мы хотим использовать наш компонент с именем `Profile`. А `Profile` содержит ещё больше HTML: ``. В конечном итоге, вот что видит браузер: From 55f3f935e8b127addf04c443f00a1460bb74f875 Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Thu, 27 Apr 2023 01:09:15 +0300 Subject: [PATCH 048/233] Update src/content/learn/conditional-rendering.md Co-authored-by: Fedya Petrakov --- src/content/learn/conditional-rendering.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/conditional-rendering.md b/src/content/learn/conditional-rendering.md index d8904dd77..831ea7269 100644 --- a/src/content/learn/conditional-rendering.md +++ b/src/content/learn/conditional-rendering.md @@ -18,7 +18,7 @@ title: Условный рендеринг ## Условно возвращаемый JSX {/*conditionally-returning-jsx*/} -Допустим, у вас есть `PackingList` компонент, который рендерит несколько `Item`, которые могут быть обозначены, как упакованные или неупавкованные: +Допустим, у вас есть компонент `PackingList`, который рендерит несколько компонентов `Item`, они могут быть обозначены, как упакованные или нет: From 3d3762accb04f7907ba92b18919d08a14c3e9b55 Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Thu, 27 Apr 2023 01:10:02 +0300 Subject: [PATCH 049/233] Update src/content/learn/conditional-rendering.md Co-authored-by: Fedya Petrakov --- src/content/learn/conditional-rendering.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/conditional-rendering.md b/src/content/learn/conditional-rendering.md index 831ea7269..d8016e75e 100644 --- a/src/content/learn/conditional-rendering.md +++ b/src/content/learn/conditional-rendering.md @@ -52,7 +52,7 @@ export default function PackingList() { -Заметь, что некоторые `Item` компоненты имеют свой `isPacked` проп, который `true` вместо `false`. Вы хотите добавить галочку (✔) к упакованным вещам, если if `isPacked={true}`. +Обратите внимание, что некоторые компоненты `Item` имеют свойство `isPacked`, со значением `true` вместо `false`. Допустим, вы хотите добавить (✔) к упакованным вещам, если if `isPacked={true}`. Вы можете писать это как [`if`/`else` условие](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Statements/if...) таким образом: From 99a883202b4dc922bc5a7365e1ace05b5c507d01 Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Thu, 27 Apr 2023 01:10:12 +0300 Subject: [PATCH 050/233] Update src/content/learn/conditional-rendering.md Co-authored-by: Fedya Petrakov --- src/content/learn/conditional-rendering.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/conditional-rendering.md b/src/content/learn/conditional-rendering.md index d8016e75e..c1ad8d179 100644 --- a/src/content/learn/conditional-rendering.md +++ b/src/content/learn/conditional-rendering.md @@ -54,7 +54,7 @@ export default function PackingList() { Обратите внимание, что некоторые компоненты `Item` имеют свойство `isPacked`, со значением `true` вместо `false`. Допустим, вы хотите добавить (✔) к упакованным вещам, если if `isPacked={true}`. -Вы можете писать это как [`if`/`else` условие](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Statements/if...) таким образом: +Можно реализовать это с помощью [управляющей конструкции `if`/`else`](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Statements/if...) таким образом: ```js if (isPacked) { From 3fa550b387153d92f336dab52d8a92e88e105c63 Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Thu, 27 Apr 2023 01:10:57 +0300 Subject: [PATCH 051/233] Update src/content/learn/conditional-rendering.md Co-authored-by: Fedya Petrakov --- src/content/learn/conditional-rendering.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/conditional-rendering.md b/src/content/learn/conditional-rendering.md index c1ad8d179..75c662d80 100644 --- a/src/content/learn/conditional-rendering.md +++ b/src/content/learn/conditional-rendering.md @@ -12,7 +12,7 @@ title: Условный рендеринг - Как вернуть разный JSX, в зависимости от его условия - Как условно включить или исключить фрагмент JSX -- Общий условный синтаксис, который вы встретите в кодовой базе React. +- Часто встречающиеся конструкции, которые вы найдете в проектах на React. From 525404a0a5060b07799904054647dfc0c940d35c Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Thu, 27 Apr 2023 01:16:12 +0300 Subject: [PATCH 052/233] Update conditional-rendering.md --- src/content/learn/conditional-rendering.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/conditional-rendering.md b/src/content/learn/conditional-rendering.md index 75c662d80..bec0d3c2b 100644 --- a/src/content/learn/conditional-rendering.md +++ b/src/content/learn/conditional-rendering.md @@ -11,7 +11,7 @@ title: Условный рендеринг - Как вернуть разный JSX, в зависимости от его условия -- Как условно включить или исключить фрагмент JSX +- Как по условию добавить или убрать часть JSX - Часто встречающиеся конструкции, которые вы найдете в проектах на React. From 261fdd9fcfa4bacadd9f0b910ed4a90b642c26a5 Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Thu, 27 Apr 2023 01:52:01 +0300 Subject: [PATCH 053/233] Update conditional-rendering.md --- src/content/learn/conditional-rendering.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/content/learn/conditional-rendering.md b/src/content/learn/conditional-rendering.md index bec0d3c2b..ee5ecf9ff 100644 --- a/src/content/learn/conditional-rendering.md +++ b/src/content/learn/conditional-rendering.md @@ -624,15 +624,15 @@ export default function PackingList() { -Помни, что ты должен писать `importance > 0 && ...` а не `importance && ...` поэтому если `importance` это `0`, то `0` не зарендерится как результат! +Помните, что вы должны писать `importance > 0 && ...` а не `importance && ...` и если `importance` это `0`, то `0` не зарендерится как результат! В этом решении, два раздельных условия были использованы, чтобы вставить пробел между именем и меткой важности. В качестве альтернативы можно использовать фрагмент с ведущим пробелом: `importance > 0 && <> ...` или добавить пробел сразу внутри тега ``: `importance > 0 && ...`. -#### Отрефактори тернарный оператор `? :` на `if` с переменной {/*refactor-a-series-of---to-if-and-variables*/} +#### Перепешите тернарный оператор `? :` на `if` с переменной {/*refactor-a-series-of---to-if-and-variables*/} -Этот `Drink` компонент использует серию `? :` условий, чтобы показать разную информацию, которая зависит от `name` пропа, который `"tea"` или `"coffee"`. Проблема в том, что информация о каждом напитке распределена по нескольким условиям. Отрефактори этот код так, чтобы использовать одно `if` условие вместо трёх `? :` условий. +Этот `Drink` компонент использует серию `? :` условий, чтобы показать разную информацию, которая зависит от `name` пропа, который `"tea"` или `"coffee"`. Проблема в том, что информация о каждом напитке распределена по нескольким условиям. Перепешите этот код так, чтобы использовать одно `if` условие вместо трёх `? :` условий. From d4c742d39f78b6b7a7ab2581aa5a13aa81e7123f Mon Sep 17 00:00:00 2001 From: Pavel Zenov Date: Thu, 27 Apr 2023 11:58:44 +0300 Subject: [PATCH 054/233] Apply suggestions from code review Co-authored-by: Anton Ahatov --- src/content/learn/index.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/content/learn/index.md b/src/content/learn/index.md index 9d1052ba4..e14bdc22e 100644 --- a/src/content/learn/index.md +++ b/src/content/learn/index.md @@ -299,7 +299,7 @@ function MyButton() { ## Обновление экрана {/*updating-the-screen*/} -Вам может понадобиться, чтобы ваш компонент "помнил" какую-то информацию и отображал её. Например, вы хотите посчитать, сколько раз была нажата кнопка. Чтобы это сделать, добавьте *состояние* в ваш компонент. +Вам может понадобиться, чтобы компонент «помнил» какую-то информацию и отображал её. Например, вы хотите посчитать сколько раз была нажата кнопка. Чтобы это сделать, добавьте *состояние* в ваш компонент. Сначала импортируйте [`useState`](/reference/react/useState) из React: @@ -382,7 +382,7 @@ button { ## Использование хуков {/*using-hooks*/} -Функции, которые начинаются с `use`, называются *хуками*. `useState` — это встроенный в React хук. В [справочнике API](/reference/react) приводятся другие встроенные хуки. Также, вы можете писать свои собственные хуки, совмещая уже существующие. +Функции, которые начинаются с `use`, называются *хуками*. `useState` — это встроенный в React хук. В [справочнике API](/reference/react) приводятся другие встроенные хуки. Также, вы можете писать свои собственные хуки, совмещая их с уже существующими. У хуков больше ограничений, чем у других функций. Хуки могут вызываться только *в начале* ваших компонентов (или других хуков). Если вам нужен `useState` в условии или цикле, выделите новый компонент и используйте его там. @@ -408,19 +408,19 @@ button { Однако, вы будете часто сталкиваться с ситуацией, когда вам будет нужно, чтобы компоненты *имели общие данные и всегда обновлялись вместе*. -Для того, чтобы оба компонента `MyButton` отображали одно и то же значение `count`, вам нужно выделить состояние из отдельных кнопок "вверх" в ближайший компонент, содержащий эти компоненты. +Для того, чтобы оба компонента `MyButton` отображали одно и то же значение `count`, вам нужно перенести состояние из отдельных кнопок «выше», в ближайший компонент, содержащий эти компоненты. В этом случае таким компонентом является `MyApp`: - + Сначала состояние `count` компонента `MyApp` равно `0` и передаётся обоим потомкам - + При клике `MyApp` обновляет своё состояние `count` на значение `1` и передаёт его вниз обоим потомкам @@ -467,7 +467,7 @@ export default function MyApp() { return (
        -

        Совместно обновляющиеся счётчики

        +

        Одновременно обновляющиеся счётчики

        @@ -475,9 +475,9 @@ export default function MyApp() { } ``` -Информация, которую вы передаёте таким образом, называется _пропсами_. Теперь у компонента `MyApp` есть состояние `count` и обработчик событий `handleClick`, *которые он передает в качестве пропсов* каждой кнопке-потомку. +Информация, которую вы передаёте таким образом, называется _пропсами_. Теперь у компонента `MyApp` есть состояние `count` и обработчик событий `handleClick`, *которые передаются в качестве пропсов* каждой кнопке. -Наконец, подправьте компонент `MyButton` так, чтобы он *считывал* пропсы, переданные от своего родителя: +Наконец, измените компонент `MyButton` так, чтобы он *считывал* пропсы, переданные от своего родителя: ```js {1,3} function MyButton({ count, onClick }) { @@ -532,6 +532,6 @@ button { ## Следующие шаги {/*next-steps*/} -Теперь вы знаете основы, как писать код для React! +Теперь вы знаете основы того, как писать код для React! Ознакомьтесь с [введением](/learn/tutorial-tic-tac-toe), в рамках которого вы сможете применить полученные знания и собрать своё первое мини-приложение на React. From 0217babeac544e3da17b6fad803037fb49d24304 Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Thu, 27 Apr 2023 12:42:09 +0300 Subject: [PATCH 055/233] Update conditional-rendering.md --- src/content/learn/conditional-rendering.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/content/learn/conditional-rendering.md b/src/content/learn/conditional-rendering.md index ee5ecf9ff..97f0594e3 100644 --- a/src/content/learn/conditional-rendering.md +++ b/src/content/learn/conditional-rendering.md @@ -10,8 +10,8 @@ title: Условный рендеринг -- Как вернуть разный JSX, в зависимости от его условия -- Как по условию добавить или убрать часть JSX +- Как вернуть разный JSX, в зависимости от ситуации. +- Как по условию добавить или убрать часть JSX. - Часто встречающиеся конструкции, которые вы найдете в проектах на React. From cabf26fc395809e21183e3463eedffd653b0ba39 Mon Sep 17 00:00:00 2001 From: avarlamova <59831804+avarlamova@users.noreply.github.com> Date: Thu, 27 Apr 2023 14:21:31 +0300 Subject: [PATCH 056/233] Update importing-and-exporting-components.md --- .../importing-and-exporting-components.md | 153 +++++++++--------- 1 file changed, 76 insertions(+), 77 deletions(-) diff --git a/src/content/learn/importing-and-exporting-components.md b/src/content/learn/importing-and-exporting-components.md index f8f55605c..0715ede6f 100644 --- a/src/content/learn/importing-and-exporting-components.md +++ b/src/content/learn/importing-and-exporting-components.md @@ -1,26 +1,26 @@ --- -title: Importing and Exporting Components +title: Импорт и экспорт компонентов --- -The magic of components lies in their reusability: you can create components that are composed of other components. But as you nest more and more components, it often makes sense to start splitting them into different files. This lets you keep your files easy to scan and reuse components in more places. +«Магия» компонентов заключается в возможности их повторного использования. Вы можете создавать компоненты, которые состоят из других компонентов. Но по мере увеличения вложенности компонентов зачастую бывает разумным разделить их на отдельные файлы. Это повышает читаемость кода и позволяет повторно использовать компоненты в большем количестве мест. -* What a root component file is -* How to import and export a component -* When to use default and named imports and exports -* How to import and export multiple components from one file -* How to split components into multiple files +* Что такое корневой компонент +* Как импортировать и экспортировать компонент +* Когда использовать дефолтные и именованные импорты и экспорты +* Как импортировать и экспортировать несколько компонентов из одного файла +* Как разделять компоненты на отдельные файлы -## The root component file {/*the-root-component-file*/} +## Корневой компоненты {/*the-root-component-file*/} -In [Your First Component](/learn/your-first-component), you made a `Profile` component and a `Gallery` component that renders it: +В разделе [Ваш первый компонент](/learn/your-first-component) вы создали компонент `Profile` и компонент `Gallery`, который рендерит его: @@ -29,7 +29,7 @@ function Profile() { return ( Katherine Johnson ); } @@ -37,7 +37,7 @@ function Profile() { export default function Gallery() { return (
        -

        Amazing scientists

        +

        Восхитительные ученые

        @@ -52,17 +52,17 @@ img { margin: 0 10px 10px 0; height: 90px; } -These currently live in a **root component file,** named `App.js` in this example. In [Create React App](https://create-react-app.dev/), your app lives in `src/App.js`. Depending on your setup, your root component could be in another file, though. If you use a framework with file-based routing, such as Next.js, your root component will be different for every page. +Эти компоненты сейчас находятся внутри **файла корневого компонента,** который в примере называется `App.js`. При использовании [Create React App](https://create-react-app.dev/) приложение находится в `src/App.js`. Однако, в зависимости от конфигурации файлов в проекте, корневой компонент может находиться в другом файле. При использовании фреймворка с маршрутизацией на основе файлов, например Next.js, корневой компонент будет разным для каждой страницы. -## Exporting and importing a component {/*exporting-and-importing-a-component*/} +## Экспорт и импорт компонентов {/*exporting-and-importing-a-component*/} -What if you want to change the landing screen in the future and put a list of science books there? Or place all the profiles somewhere else? It makes sense to move `Gallery` and `Profile` out of the root component file. This will make them more modular and reusable in other files. You can move a component in three steps: +Что, если в будущем вы захотите изменить страницу и отобразить на ней список научных книг? Или расположить профили ученых в другом месте? Кажется разумным извлечь компоненты `Gallery` и `Profile` из файла корневого компонента. Это сделает их более модульными и позволит повторно использовать их в других файлах. Переместить компонент можно в три шага: -1. **Make** a new JS file to put the components in. -2. **Export** your function component from that file (using either [default](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/export#using_the_default_export) or [named](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/export#using_named_exports) exports). -3. **Import** it in the file where you’ll use the component (using the corresponding technique for importing [default](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/import#importing_defaults) or [named](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/import#import_a_single_export_from_a_module) exports). +1. **Создайте** новый файл JS, куда вы поместите компонент. +2. **Экспортируйте** функциональный компонент из этого файла (используя или [экспорт по умолчанию](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/export#using_the_default_export) или [именованный](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/export#using_named_exports) экспорт). +3. **Импортируйте** компонент в файл, где вы будете его использовать (используя соответствующую технику для импорта значения [по умолчанию](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/import#importing_defaults) или [именованного](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/import#import_a_single_export_from_a_module) экспорта). -Here both `Profile` and `Gallery` have been moved out of `App.js` into a new file called `Gallery.js`. Now you can change `App.js` to import `Gallery` from `Gallery.js`: +В следующем примере `Profile` и `Gallery` были извлечены из `App.js` в новый файл `Gallery.js`. Теперь вы можете изменить `App.js`, добавив в него импорт компонента `Gallery` из файла `Gallery.js`: @@ -81,7 +81,7 @@ function Profile() { return ( Alan L. Hart ); } @@ -89,7 +89,7 @@ function Profile() { export default function Gallery() { return (
        -

        Amazing scientists

        +

        Восхитительные ученые

        @@ -104,60 +104,62 @@ img { margin: 0 10px 10px 0; height: 90px; } -Notice how this example is broken down into two component files now: +Обратите внимание, что код из примера теперь использует два файла компонентов: 1. `Gallery.js`: - - Defines the `Profile` component which is only used within the same file and is not exported. - - Exports the `Gallery` component as a **default export.** + - Содержит компонент `Profile`, который используется только в этом файле и не экспортируется. + - Экспортирует компонент `Gallery` **по умолчанию.** 2. `App.js`: - - Imports `Gallery` as a **default import** from `Gallery.js`. - - Exports the root `App` component as a **default export.** + - Импортирует компонент `Gallery` из `Gallery.js` **по умолчанию.** + - Экспортирует корневой компонент `App` **по умолчанию.** -You may encounter files that leave off the `.js` file extension like so: +В некоторых случаях вы можете заметить, что при импорте в именах файлов опускается расширение `.js`, например: ```js import Gallery from './Gallery'; ``` -Either `'./Gallery.js'` or `'./Gallery'` will work with React, though the former is closer to how [native ES Modules](https://developer.mozilla.org/docs/Web/JavaScript/Guide/Modules) work. +Оба варианта (`'./Gallery.js'` и `'./Gallery'`) будут работать в React, хотя первый вариант ближе к тому, как работают [нативные ES-модули](https://developer.mozilla.org/docs/Web/JavaScript/Guide/Modules). -#### Default vs named exports {/*default-vs-named-exports*/} +#### Экспорт по умолчанию и именованный экспорт {/*default-vs-named-exports*/} -There are two primary ways to export values with JavaScript: default exports and named exports. So far, our examples have only used default exports. But you can use one or both of them in the same file. **A file can have no more than one _default_ export, but it can have as many _named_ exports as you like.** +Существует два основных способа экспорта значений в JavaScript: экспорт по умолчанию и именованный экспорт. До сих пор в примерах использовался только экспорт по умолчанию. Но вы можете использовать один из этих способов или оба в одном файле. **В файле не может быть больше одного экспорта _по умолчанию_, но сколько угодно _именованных_ экспортов.** -![Default and named exports](/images/docs/illustrations/i_import-export.svg) +![Именованные экспорты и экспорты по умолчанию](/images/docs/illustrations/i_import-export.svg) -How you export your component dictates how you must import it. You will get an error if you try to import a default export the same way you would a named export! This chart can help you keep track: +Способ, которым компонент был экспортирован, определяет способ, которым его нужно импортировать. Вы получите ошибку, если попытаетесь импортировать экспортированный по умолчанию компонент так же, как компонент с именованным экспортом! Эта таблица поможет вам разобраться: -| Syntax | Export statement | Import statement | +| Синтаксис экспорта | Как экспортировать | Как импортировать | | ----------- | ----------- | ----------- | -| Default | `export default function Button() {}` | `import Button from './Button.js';` | -| Named | `export function Button() {}` | `import { Button } from './Button.js';` | +| По умолчанию | `export default function Button() {}` | `import Button from './Button.js';` | +| Именованный | `export function Button() {}` | `import { Button } from './Button.js';` | -When you write a _default_ import, you can put any name you want after `import`. For example, you could write `import Banana from './Button.js'` instead and it would still provide you with the same default export. In contrast, with named imports, the name has to match on both sides. That's why they are called _named_ imports! +При использовании импорта _по умолчанию_ можно использовать любое имя после слова `import`. Например, можно написать `import Banana from './Button.js'`, и эта запись все еще будет корректно импортировать значение по умолчанию. При использовании именованных импортов, напротив, значения должны совпадать в обоих файлах. Именно поэтому такие импорты называются _именованными_. + + +**Разработчики часто используют экспорт по умолчанию, если файл экспортирует только один компонент, и именованный экспорт, если он экспортирует несколько компонентов и значений.** Независимо от того, какой стиль написания кода вы предпочитаете, всегда давайте осмысленные имена вашим функциональным компонентам и файлам, которые их содержат. Не рекомендуется использовать компоненты без имен, такие как `export default () => {}`, поскольку это затрудняет отладку. -**People often use default exports if the file exports only one component, and use named exports if it exports multiple components and values.** Regardless of which coding style you prefer, always give meaningful names to your component functions and the files that contain them. Components without names, like `export default () => {}`, are discouraged because they make debugging harder. -## Exporting and importing multiple components from the same file {/*exporting-and-importing-multiple-components-from-the-same-file*/} +## Экспорт и импорт нескольких компонентов из одного файла {/*exporting-and-importing-multiple-components-from-the-same-file*/} -What if you want to show just one `Profile` instead of a gallery? You can export the `Profile` component, too. But `Gallery.js` already has a *default* export, and you can't have _two_ default exports. You could create a new file with a default export, or you could add a *named* export for `Profile`. **A file can only have one default export, but it can have numerous named exports!** +Что, если вы хотите показывать только один компонент `Profile` вместо всей галереи? Компонент `Profile` тоже можно экспортировать. Но в файле `Gallery.js` уже есть экспорт *по умолчанию*, а в одном файле не может быть _двух_ экспортов по умолчанию. Вы можете создать новый файл с экспортом по умолчанию или добавить *именованный* экспорт для компонента `Profile`. **В файле может быть только один экспорт по умолчанию, но несколько именованных экспортов!** -To reduce the potential confusion between default and named exports, some teams choose to only stick to one style (default or named), or avoid mixing them in a single file. Do what works best for you! +Чтобы избежать потенциальной путаницы между дефолтными и именованными экспортами, некоторые команды предпочитают придерживаться только одного стиля (экспорт по умолчанию или именованный) или не смешивать их в одном файле. Делайте то, что подходит именно вам! -First, **export** `Profile` from `Gallery.js` using a named export (no `default` keyword): +Сначала **экспортируйте** `Profile` из `Gallery.js`, используя именованный экспорт (без использования ключевого слова `default`): ```js export function Profile() { @@ -165,13 +167,13 @@ export function Profile() { } ``` -Then, **import** `Profile` from `Gallery.js` to `App.js` using a named import (with the curly braces): +Затем **импортируйте** `Profile` из `Gallery.js` в `App.js`, используя именованный импорт (с фигурными скобками): ```js import { Profile } from './Gallery.js'; ``` -Finally, **render** `` from the `App` component: +Теперь вы можете **отрендерить** `` из компонента `App`: ```js export default function App() { @@ -179,8 +181,7 @@ export default function App() { } ``` -Now `Gallery.js` contains two exports: a default `Gallery` export, and a named `Profile` export. `App.js` imports both of them. Try editing `` to `` and back in this example: - +Теперь `Gallery.js` содержит два экспорта: экспорт по умолчанию `Gallery` и именованный экспорт `Profile`. `App.js` импортирует их оба. Попробуйте изменить `` на `` и обратно в этом примере: ```js App.js @@ -199,7 +200,7 @@ export function Profile() { return ( Alan L. Hart ); } @@ -207,7 +208,7 @@ export function Profile() { export default function Gallery() { return (
        -

        Amazing scientists

        +

        Восхитительные ученые

        @@ -222,24 +223,24 @@ img { margin: 0 10px 10px 0; height: 90px; } -Now you're using a mix of default and named exports: +Теперь вы используете как именованные экспорты, так и экспорты по умолчанию: * `Gallery.js`: - - Exports the `Profile` component as a **named export called `Profile`.** - - Exports the `Gallery` component as a **default export.** + - Экспортирует компонент `Profile` как **именованный экспорт `Profile`.** + - Экспортирует компонент `Gallery` **по умолчанию.** * `App.js`: - - Imports `Profile` as a **named import called `Profile`** from `Gallery.js`. - - Imports `Gallery` as a **default import** from `Gallery.js`. - - Exports the root `App` component as a **default export.** + - Импортирует компонент `Profile` как **именованный импорт `Profile`** из файла `Gallery.js`. + - Импортирует компонент `Gallery` как **экспорт по умолчанию** из файла `Gallery.js`. + - Экспортирует корневой компонент `App` **по умолчанию.** -On this page you learned: +В этом разделе вы узнали: -* What a root component file is -* How to import and export a component -* When and how to use default and named imports and exports -* How to export multiple components from the same file +* Что такое корневой компонент +* Как импортировать и экспортировать компонент +* Когда использовать дефолтные и именованные импорты и экспорты +* Как экспортировать несколько компонентов из одного файла @@ -247,23 +248,22 @@ On this page you learned: -#### Split the components further {/*split-the-components-further*/} +#### Дальнейшее разделение компонентов {/*split-the-components-further*/} -Currently, `Gallery.js` exports both `Profile` and `Gallery`, which is a bit confusing. +Сейчас файл `Gallery.js` экспортирует два компонента (`Profile` и `Gallery`), что может немного сбивать с толку. -Move the `Profile` component to its own `Profile.js`, and then change the `App` component to render both `` and `` one after another. +Переместите компонент `Profile` в отдельный файл `Profile.js`, и затем изменить компонент `App` так, чтобы в нем друг за другом рендерились компоненты `` и ``. -You may use either a default or a named export for `Profile`, but make sure that you use the corresponding import syntax in both `App.js` and `Gallery.js`! You can refer to the table from the deep dive above: +Вы можете использовать либо экспорт по умолчанию, либо именованный экспорт для `Profile`, но убедитесь, что вы используете соответствующий синтаксис импорта как в `App.js`, так и в `Gallery.js`! Вы можете свериться с этой таблицей: -| Syntax | Export statement | Import statement | +| Синтаксис экспорта | Как экспортировать | Как импортировать | | ----------- | ----------- | ----------- | -| Default | `export default function Button() {}` | `import Button from './Button.js';` | -| Named | `export function Button() {}` | `import { Button } from './Button.js';` | +| По умолчанию | `export default function Button() {}` | `import Button from './Button.js';` | +| Именованный | `export function Button() {}` | `import { Button } from './Button.js';` | -Don't forget to import your components where they are called. Doesn't `Gallery` use `Profile`, too? - +Не забывайте импортировать компоненты там, где они используются. `Gallery` тоже использует `Profile`, не так ли? @@ -282,12 +282,12 @@ export default function App() { ``` ```js Gallery.js active -// Move me to Profile.js! +// Перемести меня в Profile.js! export function Profile() { return ( Alan L. Hart ); } @@ -295,7 +295,7 @@ export function Profile() { export default function Gallery() { return (
        -

        Amazing scientists

        +

        Восхитительные ученые

        @@ -313,12 +313,11 @@ img { margin: 0 10px 10px 0; height: 90px; } -After you get it working with one kind of exports, make it work with the other kind. +После того, как вы выполните это задание с использованием одного из типов экспорта, выполните его с использованием другого типа. -This is the solution with named exports: - +Вот решение, использующее именованные экспорты: ```js App.js @@ -341,7 +340,7 @@ import { Profile } from './Profile.js'; export default function Gallery() { return (
        -

        Amazing scientists

        +

        Восхитительные ученые

        @@ -355,7 +354,7 @@ export function Profile() { return ( Alan L. Hart ); } @@ -367,7 +366,7 @@ img { margin: 0 10px 10px 0; height: 90px; } -This is the solution with default exports: +Вот решение, использующее экспорты по умолчанию: @@ -391,7 +390,7 @@ import Profile from './Profile.js'; export default function Gallery() { return (
        -

        Amazing scientists

        +

        Восхитительные ученые

        @@ -405,7 +404,7 @@ export default function Profile() { return ( Alan L. Hart ); } From f812e06e0ca2ef8096bb8091d0661788ced71d62 Mon Sep 17 00:00:00 2001 From: avarlamova <59831804+avarlamova@users.noreply.github.com> Date: Thu, 27 Apr 2023 16:09:57 +0300 Subject: [PATCH 057/233] Update src/content/learn/importing-and-exporting-components.md Co-authored-by: Fedya Petrakov --- src/content/learn/importing-and-exporting-components.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/importing-and-exporting-components.md b/src/content/learn/importing-and-exporting-components.md index 0715ede6f..1efd134b0 100644 --- a/src/content/learn/importing-and-exporting-components.md +++ b/src/content/learn/importing-and-exporting-components.md @@ -58,7 +58,7 @@ img { margin: 0 10px 10px 0; height: 90px; } Что, если в будущем вы захотите изменить страницу и отобразить на ней список научных книг? Или расположить профили ученых в другом месте? Кажется разумным извлечь компоненты `Gallery` и `Profile` из файла корневого компонента. Это сделает их более модульными и позволит повторно использовать их в других файлах. Переместить компонент можно в три шага: -1. **Создайте** новый файл JS, куда вы поместите компонент. +1. **Создайте** новый JS файл для компонентов. 2. **Экспортируйте** функциональный компонент из этого файла (используя или [экспорт по умолчанию](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/export#using_the_default_export) или [именованный](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/export#using_named_exports) экспорт). 3. **Импортируйте** компонент в файл, где вы будете его использовать (используя соответствующую технику для импорта значения [по умолчанию](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/import#importing_defaults) или [именованного](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/import#import_a_single_export_from_a_module) экспорта). From e03d65b09c0261dbf62c64530eaaaab85024b3f4 Mon Sep 17 00:00:00 2001 From: avarlamova <59831804+avarlamova@users.noreply.github.com> Date: Thu, 27 Apr 2023 16:11:41 +0300 Subject: [PATCH 058/233] Update src/content/learn/importing-and-exporting-components.md Co-authored-by: Fedya Petrakov --- src/content/learn/importing-and-exporting-components.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/importing-and-exporting-components.md b/src/content/learn/importing-and-exporting-components.md index 1efd134b0..4382baf64 100644 --- a/src/content/learn/importing-and-exporting-components.md +++ b/src/content/learn/importing-and-exporting-components.md @@ -18,7 +18,7 @@ title: Импорт и экспорт компонентов -## Корневой компоненты {/*the-root-component-file*/} +## Файл корневого компонента {/*the-root-component-file*/} В разделе [Ваш первый компонент](/learn/your-first-component) вы создали компонент `Profile` и компонент `Gallery`, который рендерит его: From d3e5baa276149e34f67ce1699e7f1c0349d1689e Mon Sep 17 00:00:00 2001 From: avarlamova <59831804+avarlamova@users.noreply.github.com> Date: Thu, 27 Apr 2023 16:24:19 +0300 Subject: [PATCH 059/233] Update src/content/learn/importing-and-exporting-components.md Co-authored-by: Fedya Petrakov --- src/content/learn/importing-and-exporting-components.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/importing-and-exporting-components.md b/src/content/learn/importing-and-exporting-components.md index 4382baf64..0e5c80b4c 100644 --- a/src/content/learn/importing-and-exporting-components.md +++ b/src/content/learn/importing-and-exporting-components.md @@ -52,7 +52,7 @@ img { margin: 0 10px 10px 0; height: 90px; } -Эти компоненты сейчас находятся внутри **файла корневого компонента,** который в примере называется `App.js`. При использовании [Create React App](https://create-react-app.dev/) приложение находится в `src/App.js`. Однако, в зависимости от конфигурации файлов в проекте, корневой компонент может находиться в другом файле. При использовании фреймворка с маршрутизацией на основе файлов, например Next.js, корневой компонент будет разным для каждой страницы. +Эти компоненты сейчас находятся внутри **файла корневого компонента,** который в примере называется `App.js`. При использовании [Create React App](https://create-react-app.dev/) приложение находится в `src/App.js`. Однако, в зависимости от конфигурации проекта, корневой компонент может находиться в другом файле. У фреймворка с маршрутизацией на основе файлов, например Next.js, корневой компонент будет разным для каждой страницы. ## Экспорт и импорт компонентов {/*exporting-and-importing-a-component*/} From cf746918506e3bfa883ebc3ef8ccd67f652dc620 Mon Sep 17 00:00:00 2001 From: avarlamova <59831804+avarlamova@users.noreply.github.com> Date: Thu, 27 Apr 2023 16:24:47 +0300 Subject: [PATCH 060/233] Update src/content/learn/importing-and-exporting-components.md Co-authored-by: Fedya Petrakov --- src/content/learn/importing-and-exporting-components.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/importing-and-exporting-components.md b/src/content/learn/importing-and-exporting-components.md index 0e5c80b4c..521e3632a 100644 --- a/src/content/learn/importing-and-exporting-components.md +++ b/src/content/learn/importing-and-exporting-components.md @@ -56,7 +56,7 @@ img { margin: 0 10px 10px 0; height: 90px; } ## Экспорт и импорт компонентов {/*exporting-and-importing-a-component*/} -Что, если в будущем вы захотите изменить страницу и отобразить на ней список научных книг? Или расположить профили ученых в другом месте? Кажется разумным извлечь компоненты `Gallery` и `Profile` из файла корневого компонента. Это сделает их более модульными и позволит повторно использовать их в других файлах. Переместить компонент можно в три шага: +Что, если вы захотите изменить страницу и отобразить на ней список научных книг? Или переместить все профили ученых? Кажется разумным извлечь компоненты `Gallery` и `Profile` из файла корневого компонента. Это сделает их более модульными и переиспользуемыми. Переместить компонент можно за три шага: 1. **Создайте** новый JS файл для компонентов. 2. **Экспортируйте** функциональный компонент из этого файла (используя или [экспорт по умолчанию](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/export#using_the_default_export) или [именованный](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/export#using_named_exports) экспорт). From f4c0614d333c651db024cfdf20b7907aba1f98e5 Mon Sep 17 00:00:00 2001 From: Konstantin Arabei Date: Thu, 27 Apr 2023 22:24:53 +0700 Subject: [PATCH 061/233] fixes after review --- src/content/learn/your-first-component.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/content/learn/your-first-component.md b/src/content/learn/your-first-component.md index 8fdcc0901..0916b6346 100644 --- a/src/content/learn/your-first-component.md +++ b/src/content/learn/your-first-component.md @@ -18,7 +18,7 @@ title: Ваш первый компонент ## Компоненты: строительные блоки UI {/*components-ui-building-blocks*/} -В Интернете, HTML позволяет нам создавать структурированные документы с использованием встроенного набора тегов, таких как `

        ` и `
      1. `: +В интернете, HTML позволяет создавать нам структурированные документы, используя встроенный набор тегов, например `

        ` и `
      2. `: ```html
        @@ -41,7 +41,7 @@ React позволяет вам объединять разметку, CSS и Ja - Документы + Документация @@ -51,11 +51,11 @@ React позволяет вам объединять разметку, CSS и Ja ``` -По мере роста вашего проекта вы заметите, что многие из ваших дизайнов могут быть составлены с помощью переиспользования уже написанных вами компонентов, ускоряя вашу разработку. Наше оглавление выше может быть добавлено на любой экран с помощью ``! Вы также можете начать свой проект, используя тысячи компонентов с открытым исходным кодом, которые были созданы React-сообществом, например [Chakra UI](https://chakra-ui.com/) и [Material UI.](https://material-ui.com/) +По мере роста вашего проекта вы заметите, что многие из ваших дизайнов можно создать, переиспользуя уже готовые компоненты, а это ускорит разработку. Наше оглавление выше может быть добавлено на любой экран как ``! Дайте резкий старт своему проекту, используя тысячи компонентов с открытым исходным кодом, которые были созданы React-сообществом, например [Chakra UI](https://chakra-ui.com/) и [Material UI.](https://material-ui.com/) ## Определение компонента {/*defining-a-component*/} -Традиционно при создании веб-страниц разработчики размечали свой контент, а затем добавляли немного интерактивности с помощью JavaScript. Это работало отлично, когда интерактивность была просто дополнительным элементом в Интернете. Сегодня она стала обязательной для многих сайтов и всех приложений. React ставит взаимодействие на первое место, при этом используя ту же технологию: **компонент React представляет собой JavaScript-функцию, которую можно _припудрить разметкой_.** Вот как это выглядит (вы можете отредактировать пример ниже): +Раньше при создании веб-страниц разработчики размечали свой контент, а затем добавляли щепотку интерактивности с помощью JavaScript. Это работало отлично, ведь интерактивность в интернете была просто приятной мелочью. Сегодня же это обязательная часть многих сайтов, еще больше — приложений. React ставит интерактивность на первое место, при этом используя ту же технологию: **React-компонент представляет собой JavaScript-функцию, которую можно _припудрить разметкой_.** Вот как это выглядит (вы можете редактировать пример ниже): From 269e55d9f439d24275ec01a06477fc908b430999 Mon Sep 17 00:00:00 2001 From: Konstantin Arabei Date: Thu, 27 Apr 2023 22:31:30 +0700 Subject: [PATCH 062/233] fixup! fixes after review --- src/content/learn/your-first-component.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/your-first-component.md b/src/content/learn/your-first-component.md index 0916b6346..d0662e2b4 100644 --- a/src/content/learn/your-first-component.md +++ b/src/content/learn/your-first-component.md @@ -31,7 +31,7 @@ title: Ваш первый компонент
        ``` -Эта разметка представляет эту статью как `
        `, её заголовок как `

        ` и (сокращённое) оглавление как упорядоченный список `
          `. Такая разметка, в сочетании с CSS для стилизации и JavaScript для создания интерактивности, лежит в основе каждой боковой панели, аватара, модального окна, выпадающего меню — каждой части UI, которую вы видите в Интернете. +Эта разметка представляет эту статью как `
          `, её заголовок как `

          ` и (сокращённое) оглавление как упорядоченный список `
            `. Такая разметка, в сочетании с CSS для стилизации и JavaScript для создания интерактивности, лежит в основе каждой боковой панели, аватара, модального окна, выпадающего меню — каждой части UI, которую вы видите в интернете. React позволяет вам объединять разметку, CSS и JavaScript в пользовательские "компоненты", **переиспользуемые элементы UI для вашего приложения**. Код оглавления, который вы видели выше, можно превратить в компонент ``, который можно отрендерить на каждой странице. Внутри он всё ещё использует те же HTML-теги, такие как `
            `, `

            ` и т.д. From 5dbaec2a3f078fe7193c9084bc0900c1e06d939c Mon Sep 17 00:00:00 2001 From: Laroikin Date: Fri, 28 Apr 2023 05:27:49 +0900 Subject: [PATCH 063/233] add: translate rendering-lists.md into russian --- src/content/learn/rendering-lists.md | 542 ++++++++++++++------------- 1 file changed, 273 insertions(+), 269 deletions(-) diff --git a/src/content/learn/rendering-lists.md b/src/content/learn/rendering-lists.md index 45b60240b..bbd998474 100644 --- a/src/content/learn/rendering-lists.md +++ b/src/content/learn/rendering-lists.md @@ -1,74 +1,74 @@ --- -title: Rendering Lists +title: Рендер списков --- -You will often want to display multiple similar components from a collection of data. You can use the [JavaScript array methods](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array#) to manipulate an array of data. On this page, you'll use [`filter()`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) and [`map()`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/map) with React to filter and transform your array of data into an array of components. +Часто нам нужно отобразить несколько похожих компонентов из коллекции данных. Вы можете использовать [методы массивов JavaScript](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Array) для манипулирования массивом данных. На этой странице вы будете использовать [`filter()`](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) и [`map()`](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Array/map) с React для фильтрации и преобразования массива данных в массив компонентов. -* How to render components from an array using JavaScript's `map()` -* How to render only specific components using JavaScript's `filter()` -* When and why to use React keys +* Как рендерить компоненты из массива, используя `map()` +* Как рендерить только определенные компоненты, используя `filter()` +* Когда и почему использовать React ключи -## Rendering data from arrays {/*rendering-data-from-arrays*/} +## Рендер данных из массивов {/*rendering-data-from-arrays*/} -Say that you have a list of content. +Предположим, у вас есть список контента. ```js
              -
            • Creola Katherine Johnson: mathematician
            • -
            • Mario José Molina-Pasquel Henríquez: chemist
            • -
            • Mohammad Abdus Salam: physicist
            • -
            • Percy Lavon Julian: chemist
            • -
            • Subrahmanyan Chandrasekhar: astrophysicist
            • +
            • Креола Кэтрин Джонсон (Creola Katherine Johnson): математик
            • +
            • Марио Молина (Mario José Molina-Pasquel Henríquez): химик
            • +
            • Мухаммад Абдус Салам (Mohammad Abdus Salam): физик
            • +
            • Перси Джулиан (Percy Lavon Julian): химик
            • +
            • Субраманьян Чандрасекар (Subrahmanyan Chandrasekhar): астрофизик
            ``` -The only difference among those list items is their contents, their data. You will often need to show several instances of the same component using different data when building interfaces: from lists of comments to galleries of profile images. In these situations, you can store that data in JavaScript objects and arrays and use methods like [`map()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) and [`filter()`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) to render lists of components from them. +Единственная разница между этими элементами списка - их содержимое, их данные. При построении интерфейсов вам часто нужно показывать несколько экземпляров одного и того же компонента, используя разные данные: от списков комментариев до галерей профилей. В таких ситуациях вы можете хранить эти данные в объектах и массивах JavaScript и использовать методы, такие как [`map()`](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Array/map) и [`filter()`](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Array/filter), чтобы рендерить списки компонентов с данными из них. -Here’s a short example of how to generate a list of items from an array: +Вот короткий пример того, как сгенерировать список элементов из массива: -1. **Move** the data into an array: +1. **Переместите** данные в массив: ```js const people = [ - 'Creola Katherine Johnson: mathematician', - 'Mario José Molina-Pasquel Henríquez: chemist', - 'Mohammad Abdus Salam: physicist', - 'Percy Lavon Julian: chemist', - 'Subrahmanyan Chandrasekhar: astrophysicist' + 'Креола Кэтрин Джонсон (Creola Katherine Johnson): математик', + 'Марио Молина (Mario José Molina-Pasquel Henríquez): химик', + 'Мухаммад Абдус Салам (Mohammad Abdus Salam): физик', + 'Перси Джулиан (Percy Lavon Julian): химик', + 'Субраманьян Чандрасекар (Subrahmanyan Chandrasekhar): астрофизик' ]; ``` -2. **Map** the `people` members into a new array of JSX nodes, `listItems`: +2. **Преобразуйте** элементы массива `people` в новый массив JSX-узлов, `listItems`, используя метод `map()`: ```js const listItems = people.map(person =>
          1. {person}
          2. ); ``` -3. **Return** `listItems` from your component wrapped in a `
              `: +3. **Верните** `listItems` из вашего компонента, обернув их в тег`
                `: ```js return
                  {listItems}
                ; ``` -Here is the result: +Вот что должно получиться в итоге: ```js const people = [ - 'Creola Katherine Johnson: mathematician', - 'Mario José Molina-Pasquel Henríquez: chemist', - 'Mohammad Abdus Salam: physicist', - 'Percy Lavon Julian: chemist', - 'Subrahmanyan Chandrasekhar: astrophysicist' + 'Креола Кэтрин Джонсон (Creola Katherine Johnson): математик', + 'Марио Молина (Mario José Molina-Pasquel Henríquez): химик', + 'Мухаммад Абдус Салам (Mohammad Abdus Salam): физик', + 'Перси Джулиан (Percy Lavon Julian): химик', + 'Субраманьян Чандрасекар (Subrahmanyan Chandrasekhar): астрофизик' ]; export default function List() { @@ -85,7 +85,7 @@ li { margin-bottom: 10px; } -Notice the sandbox above displays a console error: +Обратите внимание, что в консоли песочницы отображается ошибка: @@ -93,47 +93,47 @@ Warning: Each child in a list should have a unique "key" prop. -You'll learn how to fix this error later on this page. Before we get to that, let's add some structure to your data. +Вы узнаете о том, как исправить эту ошибку позже на этой странице. Прежде чем перейти к этому, давайте добавим некоторую структуру к данным. -## Filtering arrays of items {/*filtering-arrays-of-items*/} +## Фильтрация массивов элементов {/*filtering-arrays-of-items*/} -This data can be structured even more. +Структуру этих данных можно улучшить. ```js const people = [{ id: 0, - name: 'Creola Katherine Johnson', - profession: 'mathematician', + name: 'Креола Кэтрин Джонсон (Creola Katherine Johnson)', + profession: 'математик', }, { id: 1, - name: 'Mario José Molina-Pasquel Henríquez', - profession: 'chemist', + name: 'Марио Молина (Mario José Molina-Pasquel Henríquez)', + profession: 'химик', }, { id: 2, - name: 'Mohammad Abdus Salam', - profession: 'physicist', + name: 'Мухаммад Абдус Салам (Mohammad Abdus Salam)', + profession: 'физик', }, { - name: 'Percy Lavon Julian', - profession: 'chemist', + name: 'Перси Джулиан (Percy Lavon Julian)', + profession: 'химик', }, { - name: 'Subrahmanyan Chandrasekhar', - profession: 'astrophysicist', + name: 'Субраманьян Чандрасекар (Subrahmanyan Chandrasekhar)', + profession: 'астрофизик', }]; ``` -Let's say you want a way to only show people whose profession is `'chemist'`. You can use JavaScript's `filter()` method to return just those people. This method takes an array of items, passes them through a “test” (a function that returns `true` or `false`), and returns a new array of only those items that passed the test (returned `true`). +Допустим, вам нужен способ отображать только людей, чья профессия `'chemist'`. Вы можете использовать метод JavaScript `filter()` чтобы вернуть только этих людей. Этот метод принимает массив элементов, пропускает их через «тест» (функция, которая возвращает `true` или `false`) и возвращает новый массив только из тех элементов, которые прошли тест (вернули `true`). -You only want the items where `profession` is `'chemist'`. The "test" function for this looks like `(person) => person.profession === 'chemist'`. Here's how to put it together: +В нашем случае мы хотим отобразить только те элементы, где `profession` является `'химик'`. «Тест» для этого выглядит так: `(person) => person.profession === 'химик'`. Вот как собрать все воедино: -1. **Create** a new array of just “chemist” people, `chemists`, by calling `filter()` on the `people` filtering by `person.profession === 'chemist'`: +1. **Создайте** новый массив только из людей с профессией `'chemist'`, вызвав `filter()` на `people` для фильтрации по `person.profession === 'химик'`: ```js const chemists = people.filter(person => - person.profession === 'chemist' + person.profession === 'химик' ); ``` -2. Now **map** over `chemists`: +2. Теперь **преобразуйте** элементы массива `chemists`: ```js {1,13} const listItems = chemists.map(person => @@ -144,14 +144,14 @@ const listItems = chemists.map(person => />

                {person.name}: - {' ' + person.profession + ' '} - known for {person.accomplishment} + {' ' + person.profession + ' '}. + Достижение: {person.accomplishment}

                ); ``` -3. Lastly, **return** the `listItems` from your component: +3. Наконец, **верните** `listItems` из вашего компонента: ```js return
                  {listItems}
                ; @@ -175,8 +175,8 @@ export default function List() { />

                {person.name}: - {' ' + person.profession + ' '} - known for {person.accomplishment} + {' ' + person.profession + ' '}. + Достижение: {person.accomplishment}

                ); @@ -187,33 +187,33 @@ export default function List() { ```js data.js export const people = [{ id: 0, - name: 'Creola Katherine Johnson', - profession: 'mathematician', - accomplishment: 'spaceflight calculations', + name: 'Креола Кэтрин Джонсон (Creola Katherine Johnson)', + profession: 'математик', + accomplishment: 'расчеты для космических полетов', imageId: 'MK3eW3A' }, { id: 1, - name: 'Mario José Molina-Pasquel Henríquez', - profession: 'chemist', - accomplishment: 'discovery of Arctic ozone hole', + name: 'Марио Молина (Mario José Molina-Pasquel Henríquez)', + profession: 'химик', + accomplishment: 'обнаружение дыр в озоновом слое', imageId: 'mynHUSa' }, { id: 2, - name: 'Mohammad Abdus Salam', - profession: 'physicist', - accomplishment: 'electromagnetism theory', + name: 'Мухаммад Абдус Салам (Mohammad Abdus Salam)', + profession: 'физик', + accomplishment: 'открытие теории электромагнетизма', imageId: 'bE7W1ji' }, { id: 3, - name: 'Percy Lavon Julian', - profession: 'chemist', - accomplishment: 'pioneering cortisone drugs, steroids and birth control pills', + name: 'Перси Джулиан (Percy Lavon Julian)', + profession: 'химик', + accomplishment: 'изобретение препаратов с кортизоном, стероидов и противозачаточных таблеток', imageId: 'IOjWm71' }, { id: 4, - name: 'Subrahmanyan Chandrasekhar', - profession: 'astrophysicist', - accomplishment: 'white dwarf star mass calculations', + name: 'Субраманьян Чандрасекар (Subrahmanyan Chandrasekhar)', + profession: 'астрофизик', + accomplishment: 'расчет массы белого карлика', imageId: 'lrWQx8l' }]; ``` @@ -244,29 +244,30 @@ img { width: 100px; height: 100px; border-radius: 50%; } -Arrow functions implicitly return the expression right after `=>`, so you didn't need a `return` statement: +Стрелочные функции неявно возвращают результат выражения сразу после `=>`, поэтому использовать ключевое слово `return` не нужно: ```js const listItems = chemists.map(person => -
              • ...
              • // Implicit return! +
              • ...
              • // Неявный возврат! ); ``` -However, **you must write `return` explicitly if your `=>` is followed by a `{` curly brace!** +Однако, **вы должны явно вызвать `return`, если после `=>` следует фигурная скобка!** + ```js -const listItems = chemists.map(person => { // Curly brace +const listItems = chemists.map(person => { // Фигурная скобка return
              • ...
              • ; }); ``` -Arrow functions containing `=> {` are said to have a ["block body".](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions#function_body) They let you write more than a single line of code, but you *have to* write a `return` statement yourself. If you forget it, nothing gets returned! +Стрелочные функции, содержащие `=> {` считаются функциями с ["блочной формой".](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Functions/Arrow_functions#%D1%82%D0%B5%D0%BB%D0%BE_%D1%84%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D0%B8) Они позволяют писать более одной строки кода, но при этом *необходимо* явно вызвать `return`. Если вы забудете это сделать, функция ничего не вернет!
                -## Keeping list items in order with `key` {/*keeping-list-items-in-order-with-key*/} +## Сохранение порядка элементов списка с помощью `key` {/*keeping-list-items-in-order-with-key*/} -Notice that all the sandboxes above show an error in the console: +Заметьте, что все песочницы выше показывают ошибку в консоли: @@ -274,7 +275,7 @@ Warning: Each child in a list should have a unique "key" prop. -You need to give each array item a `key` -- a string or a number that uniquely identifies it among other items in that array: +Для того чтобы решить эту ошибку необходимо присвоить каждому элементу массива ключ (`key`) -- строку или число, которое уникально отличает данный элемент среди других элементов этого массива: ```js
              • ...
              • @@ -282,13 +283,13 @@ You need to give each array item a `key` -- a string or a number that uniquely i -JSX elements directly inside a `map()` call always need keys! +JSX элементы, созданные внутри `map()` всегда должны иметь ключи! -Keys tell React which array item each component corresponds to, so that it can match them up later. This becomes important if your array items can move (e.g. due to sorting), get inserted, or get deleted. A well-chosen `key` helps React infer what exactly has happened, and make the correct updates to the DOM tree. +Ключи позволяют React узнать к какому элементу массива соответствует каждый компонент, чтобы позже сопоставить их. Это становится важным, если элементы массива могут перемещаться (например, из-за сортировки), добавляться или удаляться. Хорошо выбранный ключ помогает React понять, какое именно изменение произошло, и правильно обновить DOM дерево. -Rather than generating keys on the fly, you should include them in your data: +Вместо генерации ключей на лету, вы должны включать их в свои данные: @@ -305,8 +306,8 @@ export default function List() { />

                {person.name} - {' ' + person.profession + ' '} - known for {person.accomplishment} + {' ' + person.profession + ' '}. + Достижение: {person.accomplishment}

                ); @@ -316,34 +317,34 @@ export default function List() { ```js data.js active export const people = [{ - id: 0, // Used in JSX as a key - name: 'Creola Katherine Johnson', - profession: 'mathematician', - accomplishment: 'spaceflight calculations', + id: 0, // Используется в JSX в качестве ключа + name: 'Креола Кэтрин Джонсон (Creola Katherine Johnson)', + profession: 'математик', + accomplishment: 'расчеты для космических полетов', imageId: 'MK3eW3A' }, { - id: 1, // Used in JSX as a key - name: 'Mario José Molina-Pasquel Henríquez', - profession: 'chemist', - accomplishment: 'discovery of Arctic ozone hole', + id: 1, // Используется в JSX в качестве ключа + name: 'Марио Молина (Mario José Molina-Pasquel Henríquez)', + profession: 'химик', + accomplishment: 'обнаружение дыр в озоновом слое', imageId: 'mynHUSa' }, { - id: 2, // Used in JSX as a key - name: 'Mohammad Abdus Salam', - profession: 'physicist', - accomplishment: 'electromagnetism theory', + id: 2, // Используется в JSX в качестве ключа + name: 'Мухаммад Абдус Салам (Mohammad Abdus Salam)', + profession: 'физик', + accomplishment: 'открытие теории электромагнетизма', imageId: 'bE7W1ji' }, { - id: 3, // Used in JSX as a key - name: 'Percy Lavon Julian', - profession: 'chemist', - accomplishment: 'pioneering cortisone drugs, steroids and birth control pills', + id: 3, // Используется в JSX в качестве ключа + name: 'Перси Джулиан (Percy Lavon Julian)', + profession: 'химик', + accomplishment: 'изобретение препаратов с кортизоном, стероидов и противозачаточных таблеток', imageId: 'IOjWm71' }, { - id: 4, // Used in JSX as a key - name: 'Subrahmanyan Chandrasekhar', - profession: 'astrophysicist', - accomplishment: 'white dwarf star mass calculations', + id: 4, // Используется в JSX в качестве ключа + name: 'Субраманьян Чандрасекар (Subrahmanyan Chandrasekhar)', + profession: 'астрофизик', + accomplishment: 'расчет массы белого карлика', imageId: 'lrWQx8l' }]; ``` @@ -374,11 +375,11 @@ img { width: 100px; height: 100px; border-radius: 50%; } -#### Displaying several DOM nodes for each list item {/*displaying-several-dom-nodes-for-each-list-item*/} +#### Отображение нескольких DOM узлов для каждого элемента списка {/*displaying-several-dom-nodes-for-each-list-item*/} -What do you do when each item needs to render not one, but several DOM nodes? +Как поступить, если каждый элемент должен отображать не один, а несколько DOM узлов? -The short [`<>...` Fragment](/reference/react/Fragment) syntax won't let you pass a key, so you need to either group them into a single `
                `, or use the slightly longer and [more explicit `` syntax:](/reference/react/Fragment#rendering-a-list-of-fragments) +Краткий синтаксис [`<>...` фрагмента](/reference/react/Fragment) не позволяет передавать ключ, поэтому вам нужно либо объединить их в один `
                `, либо использовать немного более длинный и [более явный ``:](/reference/react/Fragment#rendering-a-list-of-fragments) ```js import { Fragment } from 'react'; @@ -393,46 +394,48 @@ const listItems = people.map(person => ); ``` -Fragments disappear from the DOM, so this will produce a flat list of `

                `, `

                `, `

                `, `

                `, and so on. +Фрагменты исчезают из DOM, поэтому это приведет к плоскому списку элементов `

                `, `

                `, `

                `, `

                `, и т.д. -### Where to get your `key` {/*where-to-get-your-key*/} +### Откуда взять ключ {/*where-to-get-your-key*/} + +Разные источники данных предоставляют разные источники для ключей: -Different sources of data provide different sources of keys: +* **Данные из базы данных:** Если ваши данные приходят с базы данных, +то вы можете использовать ключи/ID с базы данных, которые по своей природе уникальны. -* **Data from a database:** If your data is coming from a database, you can use the database keys/IDs, which are unique by nature. -* **Locally generated data:** If your data is generated and persisted locally (e.g. notes in a note-taking app), use an incrementing counter, [`crypto.randomUUID()`](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/randomUUID) or a package like [`uuid`](https://www.npmjs.com/package/uuid) when creating items. +* **Локальные данные:** Если ваши данные генерируются и хранятся локально (к примеру, заметки в приложении для ведений заметок), используйте инкрементный счетчик, [`crypto.randomUUID()`](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/randomUUID) или пакет [`uuid`](https://www.npmjs.com/package/uuid) при создании элементов. -### Rules of keys {/*rules-of-keys*/} +### Правила ключей {/*rules-of-keys*/} -* **Keys must be unique among siblings.** However, it’s okay to use the same keys for JSX nodes in _different_ arrays. -* **Keys must not change** or that defeats their purpose! Don't generate them while rendering. +* **Ключи должны быть уникальны среди своих соседних элементов.** Однако, можно использовать одинаковые ключи для JSX-узлов в _разных_ массивах. +* **Ключи не должны меняться**, так как это лишает их смысла! Не генерируйте их во время рендеринга. -### Why does React need keys? {/*why-does-react-need-keys*/} +### Почему React нужны ключи? {/*why-does-react-need-keys*/} -Imagine that files on your desktop didn't have names. Instead, you'd refer to them by their order -- the first file, the second file, and so on. You could get used to it, but once you delete a file, it would get confusing. The second file would become the first file, the third file would be the second file, and so on. +Представьте что у файлов на вашем рабочем столе не было имен. Взамен, вы бы ссылались на них по их порядку -- первый файл, второй файл, и т. д. Возможно к этому и можно привыкнуть, но когда вы удалите какой-либо файл, порядок изменится и все станет запутанным. Второй файл станет первым, третий файл станет вторым, и т. д. -File names in a folder and JSX keys in an array serve a similar purpose. They let us uniquely identify an item between its siblings. A well-chosen key provides more information than the position within the array. Even if the _position_ changes due to reordering, the `key` lets React identify the item throughout its lifetime. +Названия файлов в папке и JSX ключи в массиве имеют схожую цель. Они позволяют нам отличать элементы от их соседей. А хорошо выбранный ключ предоставляет больше информации, чем позиция в массиве. Даже если _позиция_ изменится из-за смены порядка, `key` позволит React идентифицировать элемент на протяжении всего существования элемента. -You might be tempted to use an item's index in the array as its key. In fact, that's what React will use if you don't specify a `key` at all. But the order in which you render items will change over time if an item is inserted, deleted, or if the array gets reordered. Index as a key often leads to subtle and confusing bugs. +Возможно вам захочется использовать индекс элемента в массиве в качестве ключа. В действительности, это то, что React будет использовать, если вы не укажете `key`. Но порядок, в котором вы рендерите элементы, может поменяться со временем, если элемент будет вставлен, удален или если массив будет переупорядочен. Индекс в качестве ключа часто приводит к коварным и сбивающим с толку ошибкам. -Similarly, do not generate keys on the fly, e.g. with `key={Math.random()}`. This will cause keys to never match up between renders, leading to all your components and DOM being recreated every time. Not only is this slow, but it will also lose any user input inside the list items. Instead, use a stable ID based on the data. +Аналогично, не генерируйте ключи на лету, например, с помощью `key={Math.random()}`. Это приведет к тому, что ключи никогда не будут совпадать между рендерами, что приведет к тому, что все ваши компоненты и DOM будут пересоздаваться каждый раз. Это не только медленно, но также приведет к потере любых данных введённых пользователем внутри элементов списка. Вместо этого используйте стабильный ID, основанный на данных. -Note that your components won't receive `key` as a prop. It's only used as a hint by React itself. If your component needs an ID, you have to pass it as a separate prop: ``. +Заметьте, что ваши компоненты не получат `key` в качестве пропа. Он используется только как подсказка для React. Если ваш компонент нуждается в ID, вы должны передать его как отдельный проп: ``.. -On this page you learned: +На этой странице вы узнали: -* How to move data out of components and into data structures like arrays and objects. -* How to generate sets of similar components with JavaScript's `map()`. -* How to create arrays of filtered items with JavaScript's `filter()`. -* Why and how to set `key` on each component in a collection so React can keep track of each of them even if their position or data changes. +* Как перенести данные из компонентов в структуры данных, такие как массивы и объекты. +* Как создавать коллекции схожих компонентов с помощью JavaScript `map()`. +* Как создавать массивы отфильтрованных элементов с помощью JavaScript `filter()`. +* Зачем и как присваивать ключ каждому компоненту в коллекции чтобы React мог отслеживать каждый из них, даже если их позиция или данные изменятся. @@ -442,9 +445,9 @@ On this page you learned: #### Splitting a list in two {/*splitting-a-list-in-two*/} -This example shows a list of all people. +Этот пример показывает список всех людей. -Change it to show two separate lists one after another: **Chemists** and **Everyone Else.** Like previously, you can determine whether a person is a chemist by checking if `person.profession === 'chemist'`. +Поменяйте код так, чтобы он показывал два списка один за другим: **Химики** и **Все остальные**. Как и раньше, вы можете определить, является ли человек химиком, проверив `person.profession === 'химик'`. @@ -462,13 +465,13 @@ export default function List() {

                {person.name}: {' ' + person.profession + ' '} - known for {person.accomplishment} + Достижение: {person.accomplishment}

                ); return (
                -

                Scientists

                +

                Ученые

                  {listItems}
                ); @@ -478,33 +481,33 @@ export default function List() { ```js data.js export const people = [{ id: 0, - name: 'Creola Katherine Johnson', - profession: 'mathematician', - accomplishment: 'spaceflight calculations', + name: 'Креола Кэтрин Джонсон (Creola Katherine Johnson)', + profession: 'математик', + accomplishment: 'расчеты для космических полетов', imageId: 'MK3eW3A' }, { id: 1, - name: 'Mario José Molina-Pasquel Henríquez', - profession: 'chemist', - accomplishment: 'discovery of Arctic ozone hole', + name: 'Марио Молина (Mario José Molina-Pasquel Henríquez)', + profession: 'химик', + accomplishment: 'обнаружение дыр в озоновом слое', imageId: 'mynHUSa' }, { id: 2, - name: 'Mohammad Abdus Salam', - profession: 'physicist', - accomplishment: 'electromagnetism theory', + name: 'Мухаммад Абдус Салам (Mohammad Abdus Salam)', + profession: 'физик', + accomplishment: 'открытие теории электромагнетизма', imageId: 'bE7W1ji' }, { id: 3, - name: 'Percy Lavon Julian', - profession: 'chemist', - accomplishment: 'pioneering cortisone drugs, steroids and birth control pills', + name: 'Перси Джулиан (Percy Lavon Julian)', + profession: 'химик', + accomplishment: 'изобретение препаратов с кортизоном, стероидов и противозачаточных таблеток', imageId: 'IOjWm71' }, { id: 4, - name: 'Subrahmanyan Chandrasekhar', - profession: 'astrophysicist', - accomplishment: 'white dwarf star mass calculations', + name: 'Субраманьян Чандрасекар (Subrahmanyan Chandrasekhar)', + profession: 'астрофизик', + accomplishment: 'расчет массы белого карлика', imageId: 'lrWQx8l' }]; ``` @@ -535,7 +538,7 @@ img { width: 100px; height: 100px; border-radius: 50%; } -You could use `filter()` twice, creating two separate arrays, and then `map` over both of them: +Вы можете использовать `filter()` дважды, создав два отдельных массива, а затем использовать `map()` на обоих: @@ -545,15 +548,15 @@ import { getImageUrl } from './utils.js'; export default function List() { const chemists = people.filter(person => - person.profession === 'chemist' + person.profession === 'химик' ); const everyoneElse = people.filter(person => - person.profession !== 'chemist' + person.profession !== 'химик' ); return (
                -

                Scientists

                -

                Chemists

                +

                Ученые

                +

                Химики

                  {chemists.map(person =>
                • @@ -563,13 +566,13 @@ export default function List() { />

                  {person.name}: - {' ' + person.profession + ' '} - known for {person.accomplishment} + {' ' + person.profession + ' '}. + Достижение: {person.accomplishment}

                • )}
                -

                Everyone Else

                +

                Все остальные

                  {everyoneElse.map(person =>
                • @@ -579,8 +582,8 @@ export default function List() { />

                  {person.name}: - {' ' + person.profession + ' '} - known for {person.accomplishment} + {' ' + person.profession + ' '}. + Достижение: {person.accomplishment}

                • )} @@ -593,33 +596,33 @@ export default function List() { ```js data.js export const people = [{ id: 0, - name: 'Creola Katherine Johnson', - profession: 'mathematician', - accomplishment: 'spaceflight calculations', + name: 'Креола Кэтрин Джонсон (Creola Katherine Johnson)', + profession: 'математик', + accomplishment: 'расчеты для космических полетов', imageId: 'MK3eW3A' }, { id: 1, - name: 'Mario José Molina-Pasquel Henríquez', - profession: 'chemist', - accomplishment: 'discovery of Arctic ozone hole', + name: 'Марио Молина (Mario José Molina-Pasquel Henríquez)', + profession: 'химик', + accomplishment: 'обнаружение дыр в озоновом слое', imageId: 'mynHUSa' }, { id: 2, - name: 'Mohammad Abdus Salam', - profession: 'physicist', - accomplishment: 'electromagnetism theory', + name: 'Мухаммад Абдус Салам (Mohammad Abdus Salam)', + profession: 'физик', + accomplishment: 'открытие теории электромагнетизма', imageId: 'bE7W1ji' }, { id: 3, - name: 'Percy Lavon Julian', - profession: 'chemist', - accomplishment: 'pioneering cortisone drugs, steroids and birth control pills', + name: 'Перси Джулиан (Percy Lavon Julian)', + profession: 'химик', + accomplishment: 'изобретение препаратов с кортизоном, стероидов и противозачаточных таблеток', imageId: 'IOjWm71' }, { id: 4, - name: 'Subrahmanyan Chandrasekhar', - profession: 'astrophysicist', - accomplishment: 'white dwarf star mass calculations', + name: 'Субраманьян Чандрасекар (Subrahmanyan Chandrasekhar)', + profession: 'астрофизик', + accomplishment: 'расчет массы белого карлика', imageId: 'lrWQx8l' }]; ``` @@ -648,9 +651,9 @@ img { width: 100px; height: 100px; border-radius: 50%; } -In this solution, the `map` calls are placed directly inline into the parent `
                    ` elements, but you could introduce variables for them if you find that more readable. +В данном решении, вызовы `map` помещены непосредственно в родительские элементы `
                      `, но вы можете вынести их в отдельные переменные, если cчитаете это более читабельным. -There is still a bit duplication between the rendered lists. You can go further and extract the repetitive parts into a `` component: +Между отображаемыми списками все еще существует небольшое дублирование. Вы можете пойти дальше и извлечь повторяющиеся части в компонент ``: @@ -683,20 +686,20 @@ function ListSection({ title, people }) { export default function List() { const chemists = people.filter(person => - person.profession === 'chemist' + person.profession === 'химик' ); const everyoneElse = people.filter(person => - person.profession !== 'chemist' + person.profession !== 'химик' ); return (

                      Scientists

                      @@ -707,33 +710,33 @@ export default function List() { ```js data.js export const people = [{ id: 0, - name: 'Creola Katherine Johnson', - profession: 'mathematician', - accomplishment: 'spaceflight calculations', + name: 'Креола Кэтрин Джонсон (Creola Katherine Johnson)', + profession: 'математик', + accomplishment: 'расчеты для космических полетов', imageId: 'MK3eW3A' }, { id: 1, - name: 'Mario José Molina-Pasquel Henríquez', - profession: 'chemist', - accomplishment: 'discovery of Arctic ozone hole', + name: 'Марио Молина (Mario José Molina-Pasquel Henríquez)', + profession: 'химик', + accomplishment: 'обнаружение дыр в озоновом слое', imageId: 'mynHUSa' }, { id: 2, - name: 'Mohammad Abdus Salam', - profession: 'physicist', - accomplishment: 'electromagnetism theory', + name: 'Мухаммад Абдус Салам (Mohammad Abdus Salam)', + profession: 'физик', + accomplishment: 'открытие теории электромагнетизма', imageId: 'bE7W1ji' }, { id: 3, - name: 'Percy Lavon Julian', - profession: 'chemist', - accomplishment: 'pioneering cortisone drugs, steroids and birth control pills', + name: 'Перси Джулиан (Percy Lavon Julian)', + profession: 'химик', + accomplishment: 'изобретение препаратов с кортизоном, стероидов и противозачаточных таблеток', imageId: 'IOjWm71' }, { id: 4, - name: 'Subrahmanyan Chandrasekhar', - profession: 'astrophysicist', - accomplishment: 'white dwarf star mass calculations', + name: 'Субраманьян Чандрасекар (Subrahmanyan Chandrasekhar)', + profession: 'астрофизик', + accomplishment: 'расчет массы белого карлика', imageId: 'lrWQx8l' }]; ``` @@ -762,9 +765,9 @@ img { width: 100px; height: 100px; border-radius: 50%; }
                      -A very attentive reader might notice that with two `filter` calls, we check each person's profession twice. Checking a property is very fast, so in this example it's fine. If your logic was more expensive than that, you could replace the `filter` calls with a loop that manually constructs the arrays and checks each person once. +Очень внимательный читатель мог бы заметить, что при двух вызовах `filter` мы дважды проверяем профессию каждого человека. Проверка свойства происходит очень быстро, поэтому в данном примере это нормально. Если бы ваша логика была более затратна, вы могли бы заменить вызовы `filter` циклом, который вручную создает массивы и проверяет каждого человека один раз. -In fact, if `people` never change, you could move this code out of your component. From React's perspective, all that matters is that you give it an array of JSX nodes in the end. It doesn't care how you produce that array: +К тому же, если `people` никогда не меняется, вы можете переместить этот код из вашего компонента. С точки зрения React, единственное что имеет значение, это то, что вы предоставляете массив JSX-узлов в конце. React не важно, как вы создаете этот массив: @@ -775,7 +778,7 @@ import { getImageUrl } from './utils.js'; let chemists = []; let everyoneElse = []; people.forEach(person => { - if (person.profession === 'chemist') { + if (person.profession === 'химик') { chemists.push(person); } else { everyoneElse.push(person); @@ -795,8 +798,8 @@ function ListSection({ title, people }) { />

                      {person.name}: - {' ' + person.profession + ' '} - known for {person.accomplishment} + {' ' + person.profession + ' '}. + Достижение: {person.accomplishment}

                      )} @@ -810,11 +813,11 @@ export default function List() {

                      Scientists

                      @@ -825,33 +828,33 @@ export default function List() { ```js data.js export const people = [{ id: 0, - name: 'Creola Katherine Johnson', - profession: 'mathematician', - accomplishment: 'spaceflight calculations', + name: 'Креола Кэтрин Джонсон (Creola Katherine Johnson)', + profession: 'математик', + accomplishment: 'расчеты для космических полетов', imageId: 'MK3eW3A' }, { id: 1, - name: 'Mario José Molina-Pasquel Henríquez', - profession: 'chemist', - accomplishment: 'discovery of Arctic ozone hole', + name: 'Марио Молина (Mario José Molina-Pasquel Henríquez)', + profession: 'химик', + accomplishment: 'обнаружение дыр в озоновом слое', imageId: 'mynHUSa' }, { id: 2, - name: 'Mohammad Abdus Salam', - profession: 'physicist', - accomplishment: 'electromagnetism theory', + name: 'Мухаммад Абдус Салам (Mohammad Abdus Salam)', + profession: 'физик', + accomplishment: 'открытие теории электромагнетизма', imageId: 'bE7W1ji' }, { id: 3, - name: 'Percy Lavon Julian', - profession: 'chemist', - accomplishment: 'pioneering cortisone drugs, steroids and birth control pills', + name: 'Перси Джулиан (Percy Lavon Julian)', + profession: 'химик', + accomplishment: 'изобретение препаратов с кортизоном, стероидов и противозачаточных таблеток', imageId: 'IOjWm71' }, { id: 4, - name: 'Subrahmanyan Chandrasekhar', - profession: 'astrophysicist', - accomplishment: 'white dwarf star mass calculations', + name: 'Субраманьян Чандрасекар (Subrahmanyan Chandrasekhar)', + profession: 'астрофизик', + accomplishment: 'расчет массы белого карлика', imageId: 'lrWQx8l' }]; ``` @@ -882,13 +885,13 @@ img { width: 100px; height: 100px; border-radius: 50%; } -#### Nested lists in one component {/*nested-lists-in-one-component*/} +#### Вложенные списки в одном компоненте {/*nested-lists-in-one-component*/} -Make a list of recipes from this array! For each recipe in the array, display its name as an `

                      ` and list its ingredients in a `
                        `. +Создайте список рецептов из данного массива! Для каждого рецепта в массиве отобразите название внутри `

                        ` и перечислите ингредиенты в `
                          `. -This will require nesting two different `map` calls. +Для этого потребуется вложение двух разных вызовов `map`. @@ -909,16 +912,16 @@ export default function RecipeList() { ```js data.js export const recipes = [{ id: 'greek-salad', - name: 'Greek Salad', - ingredients: ['tomatoes', 'cucumber', 'onion', 'olives', 'feta'] + name: 'Греческий салат', + ingredients: ['помидоры', 'огурец', 'лук', 'оливки', 'сыр фета'] }, { id: 'hawaiian-pizza', - name: 'Hawaiian Pizza', - ingredients: ['pizza crust', 'pizza sauce', 'mozzarella', 'ham', 'pineapple'] + name: 'Гавайская пицца', + ingredients: ['тесто для пиццы', 'соус для пиццы', 'моцарелла', 'ветчина', 'ананас'] }, { id: 'hummus', - name: 'Hummus', - ingredients: ['chickpeas', 'olive oil', 'garlic cloves', 'lemon', 'tahini'] + name: 'Хумус', + ingredients: ['нут', 'оливковое масло', 'зубчики чеснока', 'лимон', 'тахини'] }]; ``` @@ -926,7 +929,7 @@ export const recipes = [{ -Here is one way you could go about it: +Вот один из способов, как вы можете это сделать: @@ -936,7 +939,7 @@ import { recipes } from './data.js'; export default function RecipeList() { return (
                          -

                          Recipes

                          +

                          Рецепты

                          {recipes.map(recipe =>

                          {recipe.name}

                          @@ -957,28 +960,28 @@ export default function RecipeList() { ```js data.js export const recipes = [{ id: 'greek-salad', - name: 'Greek Salad', - ingredients: ['tomatoes', 'cucumber', 'onion', 'olives', 'feta'] + name: 'Греческий салат', + ingredients: ['помидоры', 'огурец', 'лук', 'оливки', 'сыр фета'] }, { id: 'hawaiian-pizza', - name: 'Hawaiian Pizza', - ingredients: ['pizza crust', 'pizza sauce', 'mozzarella', 'ham', 'pineapple'] + name: 'Гавайская пицца', + ingredients: ['тесто для пиццы', 'соус для пиццы', 'моцарелла', 'ветчина', 'ананас'] }, { id: 'hummus', - name: 'Hummus', - ingredients: ['chickpeas', 'olive oil', 'garlic cloves', 'lemon', 'tahini'] + name: 'Хумус', + ingredients: ['нут', 'оливковое масло', 'зубчики чеснока', 'лимон', 'тахини'] }]; ``` -Each of the `recipes` already includes an `id` field, so that's what the outer loop uses for its `key`. There is no ID you could use to loop over ingredients. However, it's reasonable to assume that the same ingredient won't be listed twice within the same recipe, so its name can serve as a `key`. Alternatively, you could change the data structure to add IDs, or use index as a `key` (with the caveat that you can't safely reorder ingredients). +Каждый из рецептов уже содержит поле `id`, поэтому это и используется внешним циклом в качестве ключа. Нет ID, который можно было бы использовать для перебора ингредиентов. Однако разумно предположить, что один и тот же ингредиент не будет перечислен дважды в одном рецепте, поэтому его имя может служить в качестве ключа. Как вариант, вы можете изменить структуру данных, чтобы добавить ID, или же использовать индекс в качестве ключа (с оговоркой, что вы не можете безопасно изменять порядок ингредиентов). -#### Extracting a list item component {/*extracting-a-list-item-component*/} +#### Извлечение компонента элемента списка {/*extracting-a-list-item-component*/} -This `RecipeList` component contains two nested `map` calls. To simplify it, extract a `Recipe` component from it which will accept `id`, `name`, and `ingredients` props. Where do you place the outer `key` and why? +Компонент `RecipeList` содержит два вложенных вызова map. Чтобы упростить его, извлеките компонент `Recipe`, который будет принимать пропсы `id`, `name` и `ingredients`. Где вы разместите внешний `key` и почему? @@ -988,7 +991,7 @@ import { recipes } from './data.js'; export default function RecipeList() { return (
                          -

                          Recipes

                          +

                          Рецепты

                          {recipes.map(recipe =>

                          {recipe.name}

                          @@ -1009,16 +1012,16 @@ export default function RecipeList() { ```js data.js export const recipes = [{ id: 'greek-salad', - name: 'Greek Salad', - ingredients: ['tomatoes', 'cucumber', 'onion', 'olives', 'feta'] + name: 'Греческий салат', + ingredients: ['помидоры', 'огурец', 'лук', 'оливки', 'сыр фета'] }, { id: 'hawaiian-pizza', - name: 'Hawaiian Pizza', - ingredients: ['pizza crust', 'pizza sauce', 'mozzarella', 'ham', 'pineapple'] + name: 'Гавайская пицца', + ingredients: ['тесто для пиццы', 'соус для пиццы', 'моцарелла', 'ветчина', 'ананас'] }, { id: 'hummus', - name: 'Hummus', - ingredients: ['chickpeas', 'olive oil', 'garlic cloves', 'lemon', 'tahini'] + name: 'Хумус', + ingredients: ['нут', 'оливковое масло', 'зубчики чеснока', 'лимон', 'тахини'] }]; ``` @@ -1026,7 +1029,8 @@ export const recipes = [{ -You can copy-paste the JSX from the outer `map` into a new `Recipe` component and return that JSX. Then you can change `recipe.name` to `name`, `recipe.id` to `id`, and so on, and pass them as props to the `Recipe`: + +Вы можете скопировать и вставить JSX из внешнего вызова map в новый компонент `Recipe` и вернуть этот JSX. Затем вы можете изменить `recipe.name` на `name`, `recipe.id` на `id` и т.д., и передать их в виде пропсов компоненту `Recipe`: @@ -1051,7 +1055,7 @@ function Recipe({ id, name, ingredients }) { export default function RecipeList() { return (
                          -

                          Recipes

                          +

                          Рецепты

                          {recipes.map(recipe => )} @@ -1063,51 +1067,51 @@ export default function RecipeList() { ```js data.js export const recipes = [{ id: 'greek-salad', - name: 'Greek Salad', - ingredients: ['tomatoes', 'cucumber', 'onion', 'olives', 'feta'] + name: 'Греческий салат', + ingredients: ['помидоры', 'огурец', 'лук', 'оливки', 'сыр фета'] }, { id: 'hawaiian-pizza', - name: 'Hawaiian Pizza', - ingredients: ['pizza crust', 'pizza sauce', 'mozzarella', 'ham', 'pineapple'] + name: 'Гавайская пицца', + ingredients: ['тесто для пиццы', 'соус для пиццы', 'моцарелла', 'ветчина', 'ананас'] }, { id: 'hummus', - name: 'Hummus', - ingredients: ['chickpeas', 'olive oil', 'garlic cloves', 'lemon', 'tahini'] + name: 'Хумус', + ingredients: ['нут', 'оливковое масло', 'зубчики чеснока', 'лимон', 'тахини'] }]; ``` -Here, `` is a syntax shortcut saying "pass all properties of the `recipe` object as props to the `Recipe` component". You could also write each prop explicitly: ``. +Здесь `` -- это сокращенный синтаксис, означающий "передайте все свойства объекта `recipe` как пропсы в компонент `Recipe`". Вы также можете явно задать каждый проп: ``. -**Note that the `key` is specified on the `` itself rather than on the root `
                          ` returned from `Recipe`.** This is because this `key` is needed directly within the context of the surrounding array. Previously, you had an array of `
                          `s so each of them needed a `key`, but now you have an array of ``s. In other words, when you extract a component, don't forget to leave the `key` outside the JSX you copy and paste. +**Обратите внимание, что `key` указывается на самом компоненте ``, а не на корневом `
                          `, возвращаемом из `Recipe`.** Всё потому, что этот `key` необходим непосредственно в контексте окружающего массива. Ранее у вас был массив `
                          `, поэтому каждому из них требовался ключ, но теперь у вас есть массив ``. Другими словами, когда вы извлекаете компонент, не забудьте оставить ключ за пределами JSX, который вы копируете и вставляете. -#### List with a separator {/*list-with-a-separator*/} +#### Список с разделителем {/*list-with-a-separator*/} -This example renders a famous haiku by Katsushika Hokusai, with each line wrapped in a `

                          ` tag. Your job is to insert an `


                          ` separator between each paragraph. Your resulting structure should look like this: +Данный пример рендерит известное хокку Кацусики Хокусая, каждая строка обернута в тег `

                          `. Ваша задача -- вставить разделитель `


                          ` между каждым параграфом. Ваша структура должна выглядеть так: ```js
                          -

                          I write, erase, rewrite

                          +

                          Я пишу, стираю, переписываю,


                          -

                          Erase again, and then

                          +

                          Снова стереть, а затем


                          -

                          A poppy blooms.

                          +

                          Цветет мак.

                          ``` -A haiku only contains three lines, but your solution should work with any number of lines. Note that `
                          ` elements only appear *between* the `

                          ` elements, not in the beginning or the end! +Хокку содержит только три строки, но ваше решение должно работать с любым количеством строк. Обратите внимание, что элементы `


                          ` должны быть *между* элементами `

                          `, а не в начале или в конце! ```js const poem = { lines: [ - 'I write, erase, rewrite', - 'Erase again, and then', - 'A poppy blooms.' + 'Я пишу, стираю, переписываю,', + 'Снова стереть, а затем', + 'Цветет мак.' ] }; @@ -1141,33 +1145,33 @@ hr { -(This is a rare case where index as a key is acceptable because a poem's lines will never reorder.) +(Это один из редких случаев когда можно использовать индекс в качестве ключа, потому что строки стихотворения никогда не будут переупорядочиваться.) -You'll either need to convert `map` to a manual loop, or use a fragment. +Вам понадобится либо поменять `map` на обычный цикл, либо использовать фрагмент. -You can write a manual loop, inserting `


                          ` and `

                          ...

                          ` into the output array as you go: +Вы можете использовать обычный цикл, вставляя `
                          ` и `

                          ...

                          ` в массив для вывода по мере выполнения: ```js const poem = { lines: [ - 'I write, erase, rewrite', - 'Erase again, and then', - 'A poppy blooms.' + 'Я пишу, стираю, переписываю,', + 'Снова стереть, а затем', + 'Цветет мак.' ] }; export default function Poem() { let output = []; - // Fill the output array + // Заполнение массива для вывода poem.lines.forEach((line, i) => { output.push(
                          @@ -1178,7 +1182,7 @@ export default function Poem() {

                          ); }); - // Remove the first
                          + // Убираем первый
                          output.shift(); return ( @@ -1206,9 +1210,9 @@ hr {
                          -Using the original line index as a `key` doesn't work anymore because each separator and paragraph are now in the same array. However, you can give each of them a distinct key using a suffix, e.g. `key={i + '-text'}`. +Использование исходного индекса строки в качестве ключа больше не работает, потому что теперь каждый разделитель и абзац находятся в одном и том же массиве. Однако вы можете присвоить каждому из них уникальный ключ с использованием суффикса, например, `key={i + '-text'}`. -Alternatively, you could render a collection of fragments which contain `
                          ` and `

                          ...

                          `. However, the `<>...` shorthand syntax doesn't support passing keys, so you'd have to write `` explicitly: +В качестве альтернативы, вы можете отрендерить коллекцию фрагментов, содержащих `
                          ` и `

                          ...

                          `. Однако сокращенный синтаксис `<>...` не поддерживает передачу ключей, поэтому вам придется явно использовать ``: @@ -1217,9 +1221,9 @@ import { Fragment } from 'react'; const poem = { lines: [ - 'I write, erase, rewrite', - 'Erase again, and then', - 'A poppy blooms.' + 'Я пишу, стираю, переписываю,', + 'Снова стереть, а затем', + 'Цветет мак.' ] }; @@ -1254,7 +1258,7 @@ hr { -Remember, fragments (often written as `<> `) let you group JSX nodes without adding extra `
                          `s! +Запомните, фрагменты (часто записываемые как `<> `) позволяют вам группировать JSX-узлы без добавления дополнительных `
                          `! From f8d239796164c6c057486f5f864d06a984295422 Mon Sep 17 00:00:00 2001 From: Laroikin Date: Fri, 28 Apr 2023 05:54:07 +0900 Subject: [PATCH 064/233] fix: fixing some typos and code issues --- src/content/learn/rendering-lists.md | 46 ++++++++++++++-------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/content/learn/rendering-lists.md b/src/content/learn/rendering-lists.md index bbd998474..3c1dea6f5 100644 --- a/src/content/learn/rendering-lists.md +++ b/src/content/learn/rendering-lists.md @@ -30,7 +30,7 @@ title: Рендер списков
                        ``` -Единственная разница между этими элементами списка - их содержимое, их данные. При построении интерфейсов вам часто нужно показывать несколько экземпляров одного и того же компонента, используя разные данные: от списков комментариев до галерей профилей. В таких ситуациях вы можете хранить эти данные в объектах и массивах JavaScript и использовать методы, такие как [`map()`](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Array/map) и [`filter()`](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Array/filter), чтобы рендерить списки компонентов с данными из них. +Единственная разница между этими элементами списка - их содержимое, их данные. При построении интерфейсов вам часто нужно показывать несколько экземпляров одного и того же компонента, используя различные данные: от списков комментариев до галерей профилей. В таких ситуациях вы можете хранить эти данные в объектах и массивах JavaScript и использовать методы, такие как [`map()`](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Array/map) и [`filter()`](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Array/filter), чтобы рендерить списки компонентов с данными из них. Вот короткий пример того, как сгенерировать список элементов из массива: @@ -52,7 +52,7 @@ const people = [ const listItems = people.map(person =>
                      • {person}
                      • ); ``` -3. **Верните** `listItems` из вашего компонента, обернув их в тег`
                          `: +3. **Верните** `listItems` из вашего компонента, обернув их в тег `
                            `: ```js return
                              {listItems}
                            ; @@ -121,7 +121,7 @@ const people = [{ }]; ``` -Допустим, вам нужен способ отображать только людей, чья профессия `'chemist'`. Вы можете использовать метод JavaScript `filter()` чтобы вернуть только этих людей. Этот метод принимает массив элементов, пропускает их через «тест» (функция, которая возвращает `true` или `false`) и возвращает новый массив только из тех элементов, которые прошли тест (вернули `true`). +Допустим, вам нужен способ отображать только людей, чья профессия `'химик'`. Вы можете использовать метод JavaScript `filter()` чтобы вернуть только этих людей. Этот метод принимает массив элементов, пропускает их через «тест» (функция, которая возвращает `true` или `false`) и возвращает новый массив только из тех элементов, которые прошли тест (вернули `true`). В нашем случае мы хотим отобразить только те элементы, где `profession` является `'химик'`. «Тест» для этого выглядит так: `(person) => person.profession === 'химик'`. Вот как собрать все воедино: @@ -165,7 +165,7 @@ import { getImageUrl } from './utils.js'; export default function List() { const chemists = people.filter(person => - person.profession === 'chemist' + person.profession === 'химик' ); const listItems = chemists.map(person =>
                          • @@ -189,7 +189,7 @@ export const people = [{ id: 0, name: 'Креола Кэтрин Джонсон (Creola Katherine Johnson)', profession: 'математик', - accomplishment: 'расчеты для космических полетов', + accomplishment: 'расчёты для космических полетов', imageId: 'MK3eW3A' }, { id: 1, @@ -213,7 +213,7 @@ export const people = [{ id: 4, name: 'Субраманьян Чандрасекар (Subrahmanyan Chandrasekhar)', profession: 'астрофизик', - accomplishment: 'расчет массы белого карлика', + accomplishment: 'расчёт массы белого карлика', imageId: 'lrWQx8l' }]; ``` @@ -320,7 +320,7 @@ export const people = [{ id: 0, // Используется в JSX в качестве ключа name: 'Креола Кэтрин Джонсон (Creola Katherine Johnson)', profession: 'математик', - accomplishment: 'расчеты для космических полетов', + accomplishment: 'расчёты для космических полетов', imageId: 'MK3eW3A' }, { id: 1, // Используется в JSX в качестве ключа @@ -344,7 +344,7 @@ export const people = [{ id: 4, // Используется в JSX в качестве ключа name: 'Субраманьян Чандрасекар (Subrahmanyan Chandrasekhar)', profession: 'астрофизик', - accomplishment: 'расчет массы белого карлика', + accomplishment: 'расчёт массы белого карлика', imageId: 'lrWQx8l' }]; ``` @@ -379,7 +379,7 @@ img { width: 100px; height: 100px; border-radius: 50%; } Как поступить, если каждый элемент должен отображать не один, а несколько DOM узлов? -Краткий синтаксис [`<>...` фрагмента](/reference/react/Fragment) не позволяет передавать ключ, поэтому вам нужно либо объединить их в один `
                            `, либо использовать немного более длинный и [более явный ``:](/reference/react/Fragment#rendering-a-list-of-fragments) +Краткий синтаксис [`<>...` фрагмента](/reference/react/Fragment) не позволяет передавать ключ, поэтому вам нужно либо объединить их в один `
                            `, либо использовать чуть более длинный и [более явный ``:](/reference/react/Fragment#rendering-a-list-of-fragments) ```js import { Fragment } from 'react'; @@ -414,15 +414,15 @@ const listItems = people.map(person => ### Почему React нужны ключи? {/*why-does-react-need-keys*/} -Представьте что у файлов на вашем рабочем столе не было имен. Взамен, вы бы ссылались на них по их порядку -- первый файл, второй файл, и т. д. Возможно к этому и можно привыкнуть, но когда вы удалите какой-либо файл, порядок изменится и все станет запутанным. Второй файл станет первым, третий файл станет вторым, и т. д. +Представьте что у файлов на вашем рабочем столе не было бы имен. Взамен, вы бы ссылались на них по их порядку -- первый файл, второй файл, и т.д. Возможно к этому и можно привыкнуть, но когда вы удалите какой-либо файл, порядок изменится и все станет запутанным. Второй файл станет первым, третий файл станет вторым, и т. д. -Названия файлов в папке и JSX ключи в массиве имеют схожую цель. Они позволяют нам отличать элементы от их соседей. А хорошо выбранный ключ предоставляет больше информации, чем позиция в массиве. Даже если _позиция_ изменится из-за смены порядка, `key` позволит React идентифицировать элемент на протяжении всего существования элемента. +Названия файлов в папке и JSX ключи в массиве имеют схожую цель. Они позволяют нам отличать элементы от их других элементов в массиве. А хорошо выбранный ключ предоставляет больше информации, чем позиция в массиве. Даже если _позиция_ изменится из-за смены порядка, `key` позволит React идентифицировать элемент на протяжении всего существования элемента. -Возможно вам захочется использовать индекс элемента в массиве в качестве ключа. В действительности, это то, что React будет использовать, если вы не укажете `key`. Но порядок, в котором вы рендерите элементы, может поменяться со временем, если элемент будет вставлен, удален или если массив будет переупорядочен. Индекс в качестве ключа часто приводит к коварным и сбивающим с толку ошибкам. +Возможно вам захочется использовать индекс элемента в массиве в качестве ключа. В действительности, это то, что React будет использовать, если вы не укажете `key`. Но порядок, в котором вы рендерите элементы, может поменяться со временем, если какой-либо элемент будет вставлен, удален или если массив будет переупорядочен. Индекс в качестве ключа часто приводит к коварным и сбивающим с толку ошибкам. -Аналогично, не генерируйте ключи на лету, например, с помощью `key={Math.random()}`. Это приведет к тому, что ключи никогда не будут совпадать между рендерами, что приведет к тому, что все ваши компоненты и DOM будут пересоздаваться каждый раз. Это не только медленно, но также приведет к потере любых данных введённых пользователем внутри элементов списка. Вместо этого используйте стабильный ID, основанный на данных. +Аналогично, не генерируйте ключи на лету, например, с помощью `key={Math.random()}`. Это приведет к тому, что ключи никогда не будут совпадать между рендерами, что приведет к пересозданию всех ваших компонентов и DOM каждый раз. Это не только медленно, но также приведет к потере любых данных введённых пользователем внутри элементов списка. Вместо этого используйте стабильный ID, основанный на данных. Заметьте, что ваши компоненты не получат `key` в качестве пропа. Он используется только как подсказка для React. Если ваш компонент нуждается в ID, вы должны передать его как отдельный проп: ``.. @@ -483,7 +483,7 @@ export const people = [{ id: 0, name: 'Креола Кэтрин Джонсон (Creola Katherine Johnson)', profession: 'математик', - accomplishment: 'расчеты для космических полетов', + accomplishment: 'расчёты для космических полетов', imageId: 'MK3eW3A' }, { id: 1, @@ -507,7 +507,7 @@ export const people = [{ id: 4, name: 'Субраманьян Чандрасекар (Subrahmanyan Chandrasekhar)', profession: 'астрофизик', - accomplishment: 'расчет массы белого карлика', + accomplishment: 'расчёт массы белого карлика', imageId: 'lrWQx8l' }]; ``` @@ -598,7 +598,7 @@ export const people = [{ id: 0, name: 'Креола Кэтрин Джонсон (Creola Katherine Johnson)', profession: 'математик', - accomplishment: 'расчеты для космических полетов', + accomplishment: 'расчёты для космических полетов', imageId: 'MK3eW3A' }, { id: 1, @@ -622,7 +622,7 @@ export const people = [{ id: 4, name: 'Субраманьян Чандрасекар (Subrahmanyan Chandrasekhar)', profession: 'астрофизик', - accomplishment: 'расчет массы белого карлика', + accomplishment: 'расчёт массы белого карлика', imageId: 'lrWQx8l' }]; ``` @@ -674,8 +674,8 @@ function ListSection({ title, people }) { />

                            {person.name}: - {' ' + person.profession + ' '} - known for {person.accomplishment} + {' ' + person.profession + ' '}. + Достижение: {person.accomplishment}

                          • )} @@ -712,7 +712,7 @@ export const people = [{ id: 0, name: 'Креола Кэтрин Джонсон (Creola Katherine Johnson)', profession: 'математик', - accomplishment: 'расчеты для космических полетов', + accomplishment: 'расчёты для космических полетов', imageId: 'MK3eW3A' }, { id: 1, @@ -736,7 +736,7 @@ export const people = [{ id: 4, name: 'Субраманьян Чандрасекар (Subrahmanyan Chandrasekhar)', profession: 'астрофизик', - accomplishment: 'расчет массы белого карлика', + accomplishment: 'расчёт массы белого карлика', imageId: 'lrWQx8l' }]; ``` @@ -830,7 +830,7 @@ export const people = [{ id: 0, name: 'Креола Кэтрин Джонсон (Creola Katherine Johnson)', profession: 'математик', - accomplishment: 'расчеты для космических полетов', + accomplishment: 'расчёты для космических полетов', imageId: 'MK3eW3A' }, { id: 1, @@ -854,7 +854,7 @@ export const people = [{ id: 4, name: 'Субраманьян Чандрасекар (Subrahmanyan Chandrasekhar)', profession: 'астрофизик', - accomplishment: 'расчет массы белого карлика', + accomplishment: 'расчёт массы белого карлика', imageId: 'lrWQx8l' }]; ``` From 27fc7957e9b677a3e7c0350fadc76d9301f40893 Mon Sep 17 00:00:00 2001 From: Laroikin Date: Fri, 28 Apr 2023 06:09:25 +0900 Subject: [PATCH 065/233] fix: fix stylistic mistakes --- src/content/learn/rendering-lists.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/content/learn/rendering-lists.md b/src/content/learn/rendering-lists.md index 3c1dea6f5..338f021c9 100644 --- a/src/content/learn/rendering-lists.md +++ b/src/content/learn/rendering-lists.md @@ -275,7 +275,7 @@ Warning: Each child in a list should have a unique "key" prop. -Для того чтобы решить эту ошибку необходимо присвоить каждому элементу массива ключ (`key`) -- строку или число, которое уникально отличает данный элемент среди других элементов этого массива: +Чтобы решить эту ошибку необходимо присвоить каждому элементу массива ключ (`key`) -- строку или число, которое уникально отличает данный элемент среди других элементов этого массива: ```js
                          • ...
                          • @@ -422,7 +422,7 @@ const listItems = people.map(person => Возможно вам захочется использовать индекс элемента в массиве в качестве ключа. В действительности, это то, что React будет использовать, если вы не укажете `key`. Но порядок, в котором вы рендерите элементы, может поменяться со временем, если какой-либо элемент будет вставлен, удален или если массив будет переупорядочен. Индекс в качестве ключа часто приводит к коварным и сбивающим с толку ошибкам. -Аналогично, не генерируйте ключи на лету, например, с помощью `key={Math.random()}`. Это приведет к тому, что ключи никогда не будут совпадать между рендерами, что приведет к пересозданию всех ваших компонентов и DOM каждый раз. Это не только медленно, но также приведет к потере любых данных введённых пользователем внутри элементов списка. Вместо этого используйте стабильный ID, основанный на данных. +Аналогично, не генерируйте ключи на лету, например, с помощью `key={Math.random()}`. Это приведет к тому, что ключи никогда не будут совпадать между рендерами, что приведет к пересозданию всех ваших компонентов и DOM при каждом рендере. Это не только медленно, но также приведет к потере любых данных введённых пользователем внутри элементов списка. Вместо этого используйте стабильный ID, основанный на данных. Заметьте, что ваши компоненты не получат `key` в качестве пропа. Он используется только как подсказка для React. Если ваш компонент нуждается в ID, вы должны передать его как отдельный проп: ``.. @@ -443,7 +443,7 @@ const listItems = people.map(person => -#### Splitting a list in two {/*splitting-a-list-in-two*/} +#### Разделение списка на два {/*splitting-a-list-in-two*/} Этот пример показывает список всех людей. From f42c79a30b1ed33e94b41bf820a837113bee99b5 Mon Sep 17 00:00:00 2001 From: Laroikin Date: Fri, 28 Apr 2023 06:17:01 +0900 Subject: [PATCH 066/233] fix: make it more readable --- src/content/learn/rendering-lists.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/content/learn/rendering-lists.md b/src/content/learn/rendering-lists.md index 338f021c9..9fc7bab37 100644 --- a/src/content/learn/rendering-lists.md +++ b/src/content/learn/rendering-lists.md @@ -287,7 +287,7 @@ JSX элементы, созданные внутри `map()` всегда до -Ключи позволяют React узнать к какому элементу массива соответствует каждый компонент, чтобы позже сопоставить их. Это становится важным, если элементы массива могут перемещаться (например, из-за сортировки), добавляться или удаляться. Хорошо выбранный ключ помогает React понять, какое именно изменение произошло, и правильно обновить DOM дерево. +Ключи позволяют React узнать к какому элементу массива соответствует каждый компонент, чтобы позже сопоставить их. Это важно, если элементы массива могут перемещаться (например, из-за сортировки), добавляться или удаляться. Хорошо выбранный ключ помогает React понять, какое именно изменение произошло, и правильно обновить DOM дерево. Вместо генерации ключей на лету, вы должны включать их в свои данные: @@ -402,8 +402,7 @@ const listItems = people.map(person => Разные источники данных предоставляют разные источники для ключей: -* **Данные из базы данных:** Если ваши данные приходят с базы данных, -то вы можете использовать ключи/ID с базы данных, которые по своей природе уникальны. +* **Данные из базы данных:** Если ваши данные приходят с базы данных, то вы можете использовать ключи/ID с базы данных, которые по своей природе уникальны. * **Локальные данные:** Если ваши данные генерируются и хранятся локально (к примеру, заметки в приложении для ведений заметок), используйте инкрементный счетчик, [`crypto.randomUUID()`](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/randomUUID) или пакет [`uuid`](https://www.npmjs.com/package/uuid) при создании элементов. @@ -435,7 +434,7 @@ const listItems = people.map(person => * Как перенести данные из компонентов в структуры данных, такие как массивы и объекты. * Как создавать коллекции схожих компонентов с помощью JavaScript `map()`. * Как создавать массивы отфильтрованных элементов с помощью JavaScript `filter()`. -* Зачем и как присваивать ключ каждому компоненту в коллекции чтобы React мог отслеживать каждый из них, даже если их позиция или данные изменятся. +* Зачем и как присваивать ключ каждому компоненту в коллекции, чтобы React мог отслеживать изменения каждого из них. @@ -445,7 +444,7 @@ const listItems = people.map(person => #### Разделение списка на два {/*splitting-a-list-in-two*/} -Этот пример показывает список всех людей. +Этот пример показывает список всех людей в `people`. Поменяйте код так, чтобы он показывал два списка один за другим: **Химики** и **Все остальные**. Как и раньше, вы можете определить, является ли человек химиком, проверив `person.profession === 'химик'`. @@ -765,9 +764,9 @@ img { width: 100px; height: 100px; border-radius: 50%; } -Очень внимательный читатель мог бы заметить, что при двух вызовах `filter` мы дважды проверяем профессию каждого человека. Проверка свойства происходит очень быстро, поэтому в данном примере это нормально. Если бы ваша логика была более затратна, вы могли бы заменить вызовы `filter` циклом, который вручную создает массивы и проверяет каждого человека один раз. +Очень внимательный читатель мог бы заметить, что при двух вызовах `filter` мы дважды проверяем профессию каждого человека. Проверка свойства происходит очень быстро, поэтому в данном примере это нормально. Если бы ваша логика была более затратна, вы могли бы заменить вызовы `filter` на цикл, который вручную создает массивы и проверяет каждого человека один раз. -К тому же, если `people` никогда не меняется, вы можете переместить этот код из вашего компонента. С точки зрения React, единственное что имеет значение, это то, что вы предоставляете массив JSX-узлов в конце. React не важно, как вы создаете этот массив: +К тому же, если `people` никогда не меняется, вы можете вынести этот код из вашего компонента. С точки зрения React, единственное что имеет значение, это то, что вы предоставляете массив JSX-узлов в конце. React не важно, как вы создаете этот массив: From a20d304e1581fca263df4cfc4ebcdd6d65b6bcaf Mon Sep 17 00:00:00 2001 From: Laroikin Date: Fri, 28 Apr 2023 06:26:59 +0900 Subject: [PATCH 067/233] fix: change intro text --- src/content/learn/rendering-lists.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/content/learn/rendering-lists.md b/src/content/learn/rendering-lists.md index 9fc7bab37..065911e1e 100644 --- a/src/content/learn/rendering-lists.md +++ b/src/content/learn/rendering-lists.md @@ -4,7 +4,7 @@ title: Рендер списков -Часто нам нужно отобразить несколько похожих компонентов из коллекции данных. Вы можете использовать [методы массивов JavaScript](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Array) для манипулирования массивом данных. На этой странице вы будете использовать [`filter()`](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) и [`map()`](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Array/map) с React для фильтрации и преобразования массива данных в массив компонентов. +Часто возникает необходимость отображения ряда схожих компонентов на основе набора данных. Для этого можно воспользоваться [методами массивов JavaScript](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Array) для манипулирования массивом данных. На этой странице вы будете использовать [`filter()`](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) и [`map()`](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Array/map) с React для фильтрации и преобразования массива данных в массив компонентов. @@ -12,7 +12,7 @@ title: Рендер списков * Как рендерить компоненты из массива, используя `map()` * Как рендерить только определенные компоненты, используя `filter()` -* Когда и почему использовать React ключи +* Когда и зачем использовать React ключи From 75cad8e2d78afa8667128b6c65960649bbb893c3 Mon Sep 17 00:00:00 2001 From: Laroikin Date: Fri, 28 Apr 2023 06:29:46 +0900 Subject: [PATCH 068/233] fix: remove unnecessary pronouns --- src/content/learn/rendering-lists.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/content/learn/rendering-lists.md b/src/content/learn/rendering-lists.md index 065911e1e..acb64ffb9 100644 --- a/src/content/learn/rendering-lists.md +++ b/src/content/learn/rendering-lists.md @@ -30,7 +30,7 @@ title: Рендер списков
                          ``` -Единственная разница между этими элементами списка - их содержимое, их данные. При построении интерфейсов вам часто нужно показывать несколько экземпляров одного и того же компонента, используя различные данные: от списков комментариев до галерей профилей. В таких ситуациях вы можете хранить эти данные в объектах и массивах JavaScript и использовать методы, такие как [`map()`](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Array/map) и [`filter()`](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Array/filter), чтобы рендерить списки компонентов с данными из них. +Единственная разница между этими элементами списка - их содержимое, их данные. При построении интерфейсов часто нужно показывать несколько экземпляров одного и того же компонента, используя различные данные: от списков комментариев до галерей профилей. В таких ситуациях вы можете хранить эти данные в объектах и массивах JavaScript и использовать методы, такие как [`map()`](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Array/map) и [`filter()`](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Array/filter), чтобы рендерить списки компонентов с данными из них. Вот короткий пример того, как сгенерировать список элементов из массива: @@ -379,7 +379,7 @@ img { width: 100px; height: 100px; border-radius: 50%; } Как поступить, если каждый элемент должен отображать не один, а несколько DOM узлов? -Краткий синтаксис [`<>...` фрагмента](/reference/react/Fragment) не позволяет передавать ключ, поэтому вам нужно либо объединить их в один `
                          `, либо использовать чуть более длинный и [более явный ``:](/reference/react/Fragment#rendering-a-list-of-fragments) +Краткий синтаксис [`<>...` фрагмента](/reference/react/Fragment) не позволяет передавать ключ, поэтому нужно либо объединить их в один `
                          `, либо использовать чуть более длинный и [более явный ``:](/reference/react/Fragment#rendering-a-list-of-fragments) ```js import { Fragment } from 'react'; @@ -1257,7 +1257,7 @@ hr { -Запомните, фрагменты (часто записываемые как `<> `) позволяют вам группировать JSX-узлы без добавления дополнительных `
                          `! +Запомните, фрагменты (часто записываемые как `<> `) позволяют группировать JSX-узлы без добавления дополнительных `
                          `! From 66bf16adec05c3ce7a5fd497c9a8ccd56d6051a9 Mon Sep 17 00:00:00 2001 From: Laroikin Date: Fri, 28 Apr 2023 06:35:20 +0900 Subject: [PATCH 069/233] fix: fix code examples --- src/content/learn/rendering-lists.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/content/learn/rendering-lists.md b/src/content/learn/rendering-lists.md index acb64ffb9..73bcb8d9f 100644 --- a/src/content/learn/rendering-lists.md +++ b/src/content/learn/rendering-lists.md @@ -144,7 +144,7 @@ const listItems = chemists.map(person => />

                          {person.name}: - {' ' + person.profession + ' '}. + {' ' + person.profession}. Достижение: {person.accomplishment}

                          @@ -175,7 +175,7 @@ export default function List() { />

                          {person.name}: - {' ' + person.profession + ' '}. + {' ' + person.profession}. Достижение: {person.accomplishment}

                          @@ -306,7 +306,7 @@ export default function List() { />

                          {person.name} - {' ' + person.profession + ' '}. + {' ' + person.profession}. Достижение: {person.accomplishment}

                          @@ -463,7 +463,7 @@ export default function List() { />

                          {person.name}: - {' ' + person.profession + ' '} + {' ' + person.profession}. Достижение: {person.accomplishment}

                          @@ -565,7 +565,7 @@ export default function List() { />

                          {person.name}: - {' ' + person.profession + ' '}. + {' ' + person.profession}. Достижение: {person.accomplishment}

                          @@ -581,7 +581,7 @@ export default function List() { />

                          {person.name}: - {' ' + person.profession + ' '}. + {' ' + person.profession}. Достижение: {person.accomplishment}

                          @@ -673,7 +673,7 @@ function ListSection({ title, people }) { />

                          {person.name}: - {' ' + person.profession + ' '}. + {' ' + person.profession}. Достижение: {person.accomplishment}

                          @@ -797,7 +797,7 @@ function ListSection({ title, people }) { />

                          {person.name}: - {' ' + person.profession + ' '}. + {' ' + person.profession}. Достижение: {person.accomplishment}

                          @@ -902,7 +902,7 @@ import { recipes } from './data.js'; export default function RecipeList() { return (
                          -

                          Recipes

                          +

                          Рецепты

                          ); } From ec958903d9fc6cb47ae609b60e622327693d0f10 Mon Sep 17 00:00:00 2001 From: Viacheslav Makarov <9768704+mekarthedev@users.noreply.github.com> Date: Thu, 27 Apr 2023 23:38:03 +0200 Subject: [PATCH 070/233] Translate useId reference to russian --- src/content/reference/react/useId.md | 94 ++++++++++++++-------------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/src/content/reference/react/useId.md b/src/content/reference/react/useId.md index 4ea029f27..6ef7dfae7 100644 --- a/src/content/reference/react/useId.md +++ b/src/content/reference/react/useId.md @@ -4,7 +4,7 @@ title: useId -`useId` is a React Hook for generating unique IDs that can be passed to accessibility attributes. +`useId` -- хук для генерации уникальных идентификаторов, которые можно использовать, например, в атрибутах доступности. ```js const id = useId() @@ -16,11 +16,11 @@ const id = useId() --- -## Reference {/*reference*/} +## Справочник {/*reference*/} ### `useId()` {/*useid*/} -Call `useId` at the top level of your component to generate a unique ID: +Чтобы создать уникальный идентификатор, вызовите `useId` на верхнем уровне своего компонента: ```js import { useId } from 'react'; @@ -30,35 +30,35 @@ function PasswordField() { // ... ``` -[See more examples below.](#usage) +[См. другие примеры ниже.](#usage) -#### Parameters {/*parameters*/} +#### Параметры {/*parameters*/} -`useId` does not take any parameters. +`useId` не принимает параметров. -#### Returns {/*returns*/} +#### Возвращаемое значение {/*returns*/} -`useId` returns a unique ID string associated with this particular `useId` call in this particular component. +`useId` возвращает уникальный идентификатор, привязанный к данному конкретному вызову `useId` в данном конкретном компоненте. -#### Caveats {/*caveats*/} +#### Замечания {/*caveats*/} -* `useId` is a Hook, so you can only call it **at the top level of your component** or your own Hooks. You can't call it inside loops or conditions. If you need that, extract a new component and move the state into it. +* `useId` -- это хук. Поэтому его можно вызывать только **на верхнем уровне кода вашего компонента** или хука. Его нельзя вызывать внутри циклов и условий. Если это всё же для чего-то нужно, выделите этот вызов в отдельный компонент, который затем можно рендерить по условию или в цикле. -* `useId` **should not be used to generate keys** in a list. [Keys should be generated from your data.](/learn/rendering-lists#where-to-get-your-key) +* `useId` **не должен использоваться для создания ключей** в списках. [Ключи должны выбираться на основе данных.](/learn/rendering-lists#where-to-get-your-key) --- -## Usage {/*usage*/} +## Использование {/*usage*/} -**Do not call `useId` to generate keys in a list.** [Keys should be generated from your data.](/learn/rendering-lists#where-to-get-your-key) +**Не используйте `useId` для создания ключей** в списках. [Ключи должны выбираться на основе данных.](/learn/rendering-lists#where-to-get-your-key) -### Generating unique IDs for accessibility attributes {/*generating-unique-ids-for-accessibility-attributes*/} +### Создание уникальных идентификаторов для атрибутов доступности {/*generating-unique-ids-for-accessibility-attributes*/} -Call `useId` at the top level of your component to generate a unique ID: +Чтобы получить уникальный идентификатор, вызовите `useId` на верхнем уровне своего компонента: ```js [[1, 4, "passwordHintId"]] import { useId } from 'react'; @@ -68,7 +68,7 @@ function PasswordField() { // ... ``` -You can then pass the generated ID to different attributes: +После чего вы можете указывать этот сгенерированный идентификатор в различных атрибутах: ```js [[1, 2, "passwordHintId"], [1, 3, "passwordHintId"]] <> @@ -77,26 +77,26 @@ You can then pass the generated ID to different at ``` -**Let's walk through an example to see when this is useful.** +**Разберем на примере, когда это может быть полезно.** -[HTML accessibility attributes](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA) like [`aria-describedby`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-describedby) let you specify that two tags are related to each other. For example, you can specify that an element (like an input) is described by another element (like a paragraph). +[HTML-атрибуты доступности](https://developer.mozilla.org/ru/docs/Web/Accessibility/ARIA), такие как [`aria-describedby`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-describedby), позволяют обозначать смысловую связь между тегами. Например, можно указать, что некоторый элемент разметки (параграф) содержит краткое описание другого элемента (поля ввода). -In regular HTML, you would write it like this: +В обычном HTML вы могли бы описать это так: ```html {5,8}

                          - The password should contain at least 18 characters + Пароль должен содержать не менее 18 символов

                          ``` -However, hardcoding IDs like this is not a good practice in React. A component may be rendered more than once on the page--but IDs have to be unique! Instead of hardcoding an ID, generate a unique ID with `useId`: +Однако в React подобным образом фиксировать идентификаторы в коде -- не лучшая практика. Один и тот же компонент может использоваться в нескольких разных местах -- но ведь в каждом случае идентификаторы должны быть уникальны! Поэтому вместо фиксированного идентификатора лучше сгенерировать уникальный с помощью `useId`: ```js {4,11,14} import { useId } from 'react'; @@ -106,21 +106,21 @@ function PasswordField() { return ( <>

                          - The password should contain at least 18 characters + Пароль должен содержать не менее 18 символов

                          ); } ``` -Now, even if `PasswordField` appears multiple times on the screen, the generated IDs won't clash. +В итоге, сгенерированные идентификаторы не будут конфликтовать, даже если использовать `PasswordField` на экране в нескольких местах. @@ -132,14 +132,14 @@ function PasswordField() { return ( <>

                          - The password should contain at least 18 characters + Пароль должен содержать не менее 18 символов

                          ); @@ -148,9 +148,9 @@ function PasswordField() { export default function App() { return ( <> -

                          Choose password

                          +

                          Выберите пароль

                          -

                          Confirm password

                          +

                          Подтвердите пароль

                          ); @@ -163,33 +163,33 @@ input { margin: 5px; }
                          -[Watch this video](https://www.youtube.com/watch?v=0dNzNcuEuOo) to see the difference in the user experience with assistive technologies. +[Посмотрите видео-демонстрацию](https://www.youtube.com/watch?v=0dNzNcuEuOo) о том, как всё это влияет на опыт использования вспомогательных технологий. -With [server rendering](/reference/react-dom/server), **`useId` requires an identical component tree on the server and the client**. If the trees you render on the server and the client don't match exactly, the generated IDs won't match. +При использовании вместе с [серверным рендерингом](/reference/react-dom/server) **`useId` требует, чтобы деревья компонентов на сервере и на клиенте получались идентичными**. Если отрендеренные на сервере и на клиенте деревья не совпадут, то сгенерироованные на сервере идентификаторы не совпадут со сгенерированными на клиенте. -#### Why is useId better than an incrementing counter? {/*why-is-useid-better-than-an-incrementing-counter*/} +#### Чем `useId` лучше обычного инкрементируемого счётчика? {/*why-is-useid-better-than-an-incrementing-counter*/} -You might be wondering why `useId` is better than incrementing a global variable like `nextId++`. +Возможно вы задаётесь вопросом, почему лучше использовать `useId`, а не просто постоянно увеличивать некий глобальный счётчик -- наподобие `nextId++`. -The primary benefit of `useId` is that React ensures that it works with [server rendering.](/reference/react-dom/server) During server rendering, your components generate HTML output. Later, on the client, [hydration](/reference/react-dom/client/hydrateRoot) attaches your event handlers to the generated HTML. For hydration to work, the client output must match the server HTML. +Главное преимущество `useId` в том, что React гарантирует его корректную работу с [серверным рендерингом](/reference/react-dom/server). В процессе серверного рендеринга ваши компоненты рендерятся в обычный HTML, к которому затем на клиенте при [гидратации](/reference/react-dom/client/hydrateRoot) подключаются ваши обработчики событий. Чтобы гидратация сработала правильно, результат рендеринга на клиенте должен совпадать с полученным от сервера HTML. -This is very difficult to guarantee with an incrementing counter because the order in which the client components are hydrated may not match the order in which the server HTML was emitted. By calling `useId`, you ensure that hydration will work, and the output will match between the server and the client. +Но этого совпадения очень сложно добиться, если пользоваться обычным инкрементируемым счётчиком, потому что порядок гидратации компонентов на клиенте может не совпадать с порядком, в котором HTML рендерился на сервере. А используя `useId`, вы гарантируете, что созданные идентификаторы на сервере и на клиенте будут совпадать, и гидратация выполнится правильно. -Inside React, `useId` is generated from the "parent path" of the calling component. This is why, if the client and the server tree are the same, the "parent path" will match up regardless of rendering order. +Внутри React `useId` вычисляется на основе "пути из цепочки родителей" того компонента, который вызывает `useId`. А если отрендеренные на сервере и на клиенте деревья компонентов совпадают, то и полный "путь из цепочки родителей" для каждого компонента будет совпадать, в каком бы порядке они не рендерились. --- -### Generating IDs for several related elements {/*generating-ids-for-several-related-elements*/} +### Создание идентификаторов для нескольких элементов {/*generating-ids-for-several-related-elements*/} -If you need to give IDs to multiple related elements, you can call `useId` to generate a shared prefix for them: +Если вам нужны разные идентификаторы для нескольких элементов, и эти элементы как-то связаны по смыслу, то с помощью `useId` вы можете создать один общий для всех префикс: @@ -200,10 +200,10 @@ export default function Form() { const id = useId(); return (
                          - +
                          - +
                          ); @@ -216,20 +216,20 @@ input { margin: 5px; }
                          -This lets you avoid calling `useId` for every single element that needs a unique ID. +Так можно обойтись без лишних вызовов `useId` на каждый элемент, которому понадобился идентификатор. --- -### Specifying a shared prefix for all generated IDs {/*specifying-a-shared-prefix-for-all-generated-ids*/} +### Задание общего префикса для всех идентификаторов вообще {/*specifying-a-shared-prefix-for-all-generated-ids*/} -If you render multiple independent React applications on a single page, pass `identifierPrefix` as an option to your [`createRoot`](/reference/react-dom/client/createRoot#parameters) or [`hydrateRoot`](/reference/react-dom/client/hydrateRoot) calls. This ensures that the IDs generated by the two different apps never clash because every identifier generated with `useId` will start with the distinct prefix you've specified. +Если вы отображаете несколько независимых React-приложений на одной странице, то в вызовах [`createRoot`](/reference/react-dom/client/createRoot#parameters) и [`hydrateRoot`](/reference/react-dom/client/hydrateRoot) вы можете указать опцию `identifierPrefix`. Поскольку каждый результат вызова `useId` будет иметь указанный в опции префикс, то так можно гарантировать, что идентификаторы, сгенерированные этими двумя приложениями, никогда не будут пересекаться. ```html index.html - My app + Мое приложение
                          @@ -246,14 +246,14 @@ function PasswordField() { return ( <>

                          - The password should contain at least 18 characters + Пароль должен содержать не менее 18 символов

                          ); @@ -262,7 +262,7 @@ function PasswordField() { export default function App() { return ( <> -

                          Choose password

                          +

                          Выберите пароль

                          ); From 3fd4c7f07913ee31803b15f05869c4666f18fb4d Mon Sep 17 00:00:00 2001 From: Viacheslav Makarov <9768704+mekarthedev@users.noreply.github.com> Date: Fri, 28 Apr 2023 00:44:44 +0200 Subject: [PATCH 071/233] better wording --- src/content/reference/react/useId.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/content/reference/react/useId.md b/src/content/reference/react/useId.md index 6ef7dfae7..266b28709 100644 --- a/src/content/reference/react/useId.md +++ b/src/content/reference/react/useId.md @@ -79,7 +79,7 @@ function PasswordField() { **Разберем на примере, когда это может быть полезно.** -[HTML-атрибуты доступности](https://developer.mozilla.org/ru/docs/Web/Accessibility/ARIA), такие как [`aria-describedby`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-describedby), позволяют обозначать смысловую связь между тегами. Например, можно указать, что некоторый элемент разметки (параграф) содержит краткое описание другого элемента (поля ввода). +[HTML-атрибуты доступности](https://developer.mozilla.org/ru/docs/Web/Accessibility/ARIA), такие как [`aria-describedby`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-describedby), позволяют обозначать смысловую связь между тегами. Например, можно указать, что некоторый элемент разметки (абзац) содержит краткое описание другого элемента (поля ввода). В обычном HTML вы могли бы описать это так: @@ -177,9 +177,9 @@ input { margin: 5px; } Возможно вы задаётесь вопросом, почему лучше использовать `useId`, а не просто постоянно увеличивать некий глобальный счётчик -- наподобие `nextId++`. -Главное преимущество `useId` в том, что React гарантирует его корректную работу с [серверным рендерингом](/reference/react-dom/server). В процессе серверного рендеринга ваши компоненты рендерятся в обычный HTML, к которому затем на клиенте при [гидратации](/reference/react-dom/client/hydrateRoot) подключаются ваши обработчики событий. Чтобы гидратация сработала правильно, результат рендеринга на клиенте должен совпадать с полученным от сервера HTML. +Главное преимущество `useId` в том, что React гарантирует его корректную работу с [серверным рендерингом](/reference/react-dom/server). В процессе серверного рендеринга ваши компоненты создают HTML, к которому затем на клиенте при [гидратации](/reference/react-dom/client/hydrateRoot) подключаются ваши обработчики событий. Чтобы гидратация сработала правильно, клиентский вывод должен совпасть с полученным от сервера HTML. -Но этого совпадения очень сложно добиться, если пользоваться обычным инкрементируемым счётчиком, потому что порядок гидратации компонентов на клиенте может не совпадать с порядком, в котором HTML рендерился на сервере. А используя `useId`, вы гарантируете, что созданные идентификаторы на сервере и на клиенте будут совпадать, и гидратация выполнится правильно. +Однако крайне трудно быть уверенным, что они совпадут, если пользоваться обычным инкрементируемым счётчиком. Ведь порядок гидратации компонентов на клиенте может не совпадать с порядком, в котором HTML составлялся на сервере. Используя же `useId`, вы гарантируете, что созданные идентификаторы на сервере и на клиенте будут совпадать, и гидратация выполнится правильно. Внутри React `useId` вычисляется на основе "пути из цепочки родителей" того компонента, который вызывает `useId`. А если отрендеренные на сервере и на клиенте деревья компонентов совпадают, то и полный "путь из цепочки родителей" для каждого компонента будет совпадать, в каком бы порядке они не рендерились. @@ -222,7 +222,7 @@ input { margin: 5px; } ### Задание общего префикса для всех идентификаторов вообще {/*specifying-a-shared-prefix-for-all-generated-ids*/} -Если вы отображаете несколько независимых React-приложений на одной странице, то в вызовах [`createRoot`](/reference/react-dom/client/createRoot#parameters) и [`hydrateRoot`](/reference/react-dom/client/hydrateRoot) вы можете указать опцию `identifierPrefix`. Поскольку каждый результат вызова `useId` будет иметь указанный в опции префикс, то так можно гарантировать, что идентификаторы, сгенерированные этими двумя приложениями, никогда не будут пересекаться. +Если вы отображаете несколько независимых React-приложений на одной странице, то в вызовах [`createRoot`](/reference/react-dom/client/createRoot#parameters) и [`hydrateRoot`](/reference/react-dom/client/hydrateRoot) вы можете указать опцию `identifierPrefix`. Поскольку все полученные из `useId` идентификаторы будут с префиксом, указанным в этой опции, то так можно гарантировать, что сгенерированные разными приложениями идентификаторы никогда не пересекутся. From a1957ad37899059a82322d6c932e18d6a9b19b47 Mon Sep 17 00:00:00 2001 From: Viacheslav Makarov <9768704+mekarthedev@users.noreply.github.com> Date: Fri, 28 Apr 2023 01:01:24 +0200 Subject: [PATCH 072/233] Fix yo --- src/content/reference/react/useId.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/content/reference/react/useId.md b/src/content/reference/react/useId.md index 266b28709..a05d3f659 100644 --- a/src/content/reference/react/useId.md +++ b/src/content/reference/react/useId.md @@ -77,7 +77,7 @@ function PasswordField() { ``` -**Разберем на примере, когда это может быть полезно.** +**Разберём на примере, когда это может быть полезно.** [HTML-атрибуты доступности](https://developer.mozilla.org/ru/docs/Web/Accessibility/ARIA), такие как [`aria-describedby`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-describedby), позволяют обозначать смысловую связь между тегами. Например, можно указать, что некоторый элемент разметки (абзац) содержит краткое описание другого элемента (поля ввода). @@ -229,7 +229,7 @@ input { margin: 5px; } ```html index.html - Мое приложение + Моё приложение
                          From d368590e66b275be4201f2e29cec4a334167f256 Mon Sep 17 00:00:00 2001 From: Maxim Titov Date: Fri, 28 Apr 2023 12:12:36 +0600 Subject: [PATCH 073/233] add minor improvements based on open discussions --- src/content/learn/start-a-new-react-project.md | 12 ++++++------ src/sidebarLearn.json | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/content/learn/start-a-new-react-project.md b/src/content/learn/start-a-new-react-project.md index 7e2326c0a..c59118f77 100644 --- a/src/content/learn/start-a-new-react-project.md +++ b/src/content/learn/start-a-new-react-project.md @@ -1,5 +1,5 @@ --- -title: Создаём новый проект с React +title: Начать новый React-проект --- @@ -18,7 +18,7 @@ title: Создаём новый проект с React ### Next.js {/*nextjs*/} -**[Next.js](https://nextjs.org/) -- универсальный фулстек-фреймворк.** С его помощью вы можете создавать сайты любого размера от простого статического блога до сложного динамического приложения. Для создания нового Next.js проекта выполните команду в терминале: +**[Next.js](https://nextjs.org/) -- универсальный фулстек-фреймворк.** С его помощью вы можете создавать сайты любого размера от простого статического блога до сложного динамического приложения. Для создания нового Next.js-проекта выполните команду в терминале: npx create-next-app @@ -26,7 +26,7 @@ npx create-next-app Узнайте больше о Next.js из [официальной документации.](https://nextjs.org/learn/foundations/about-nextjs) -Команда [Vercel](https://vercel.com/) постоянно улучшает Next.js. Вы можете [развернуть Next.js приложение](https://nextjs.org/docs/deployment) на облачном хостинге с Node.js или бессерверными вычислениями, а также на вашем собственном сервере. [Полностью статические Next.js приложения](https://nextjs.org/docs/advanced-features/static-html-export) могут быть опубликованы на любом статическом хостинге. +Команда [Vercel](https://vercel.com/) постоянно улучшает Next.js. Вы можете [развернуть Next.js-приложение](https://nextjs.org/docs/deployment) на облачном хостинге с Node.js или бессерверными вычислениями, а также на вашем собственном сервере. [Полностью статические Next.js-приложения](https://nextjs.org/docs/advanced-features/static-html-export) могут быть опубликованы на любом статическом хостинге. ### Remix {/*remix*/} @@ -72,7 +72,7 @@ npx create-expo-app И вот почему. -Даже если поначалу вам не понадобились маршрутизация или загрузка данных, скорее всего вы захотите добавить библиотеки для их поддержки позже. Ваш JavaScript бандл будет расти вместе с вашим приложением, и вам придётся задуматься как разделять код для разных маршрутов. Ваше приложение будет загружать всё больше данных, и в итоге вы можете столкнуться с каскадными запросами, которые замедлят ваше приложение. Среди ваших пользователей появятся те, кто пользуется низкоскоростным интернетом или старыми устройствами, и вы захотите генерировать HTML на сервере или во время сборки. Поменять настройки большого проекта так, чтобы запускать код на сервере, может оказаться затруднительным. +Даже если поначалу вам не понадобились маршрутизация или загрузка данных, скорее всего, вы захотите добавить библиотеки для их поддержки позже. Ваш JavaScript-бандл будет расти вместе с вашим приложением, и вам придётся задуматься как разделять код для разных маршрутов. Ваше приложение будет загружать всё больше данных, и в итоге вы можете столкнуться с каскадными запросами, которые замедлят ваше приложение. Среди ваших пользователей появятся те, кто пользуется низкоскоростным интернетом или старыми устройствами, и вы захотите генерировать HTML на сервере или во время сборки. Поменять настройки большого проекта так, чтобы запускать код на сервере, может оказаться затруднительным. **Эти проблемы не являются специфичными для React. У Svelte есть SvelteKit, у Vue -- Nuxt, и т.д.** Чтобы решить эти проблемы, вам придётся интегрировать ваш бандлер с выбранными библиотеками для маршрутизации и загрузки данных. Сделать первичную настройку и заставить всё это работать вместе может оказаться не так сложно, но вам придётся поддерживать производительность приложения по мере его роста и узнать о множестве подводных камней. Вы захотите отправлять как можно меньше кода, и в то же время уменьшить количество взаимодействий между клиентом и сервером, а ещё параллельно загружать необходимые для страницы данные. Вы можете захотеть, чтобы страница была интерактивной ещё до запуска Javascript-кода, и пользователи любых браузеров могли работать с ней одинаково. Или вам потребуется добавить папку статических HTML-файлов для маркетинговых страниц, которые могут работать с отключённым на странице Javascript. Поддержка этих возможностей требует большого труда. @@ -91,7 +91,7 @@ npx create-expo-app **[Маршрутизатор приложения Next.js (Next.js App Router)](https://beta.nextjs.org/docs/getting-started) -- обновлённый API Next.js, отвечающий тому, как команда React видит архитектуру фулстек-приложений сегодня.** Маршрутизатор позволяет загружать данные в асинхронных компонентах на сервере или во время сборки. -Команда [Vercel](https://vercel.com/) постоянно улучшает Next.js. Вы можете [развернуть Next.js приложение](https://nextjs.org/docs/deployment) на облачном хостинге с Node.js или бессерверными вычислениями, а также на вашем собственном сервере. Next.js также поддерживает [статический экспорт](https://beta.nextjs.org/docs/configuring/static-export), который не требует сервера. +Команда [Vercel](https://vercel.com/) постоянно улучшает Next.js. Вы можете [развернуть Next.js-приложение](https://nextjs.org/docs/deployment) на облачном хостинге с Node.js или бессерверными вычислениями, а также на вашем собственном сервере. Next.js также поддерживает [статический экспорт](https://beta.nextjs.org/docs/configuring/static-export), который не требует сервера. @@ -113,7 +113,7 @@ async function Talks({ confId }) { // 1. Это серверный код, вы можете напрямую обратиться к вашей базе данных без запросов к API. const talks = await db.Talks.findAll({ confId }); - // 2. Добавьте любую логику рендеринга. Это не увеличит ваш JavaScript бандл. + // 2. Добавьте любую логику рендеринга. Это не увеличит ваш JavaScript-бандл. const videos = talks.map(talk => talk.video); // 3. Передайте данные ниже по дереву в компонент, который будет запускаться в браузере. diff --git a/src/sidebarLearn.json b/src/sidebarLearn.json index 3aafad3e4..4683548e3 100644 --- a/src/sidebarLearn.json +++ b/src/sidebarLearn.json @@ -25,7 +25,7 @@ "path": "/learn/installation", "routes": [ { - "title": "Создаём новый проект с React", + "title": "Начать новый React-проект", "path": "/learn/start-a-new-react-project" }, { From 62fd47e5c23a6698b85f7b733e83d1d96a2b60f9 Mon Sep 17 00:00:00 2001 From: Viacheslav Makarov <9768704+mekarthedev@users.noreply.github.com> Date: Fri, 28 Apr 2023 23:18:28 +0200 Subject: [PATCH 074/233] Translated the reference part of useDeferredValue --- .../reference/react/useDeferredValue.md | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/content/reference/react/useDeferredValue.md b/src/content/reference/react/useDeferredValue.md index 3f2a8a5d9..ea18c49a8 100644 --- a/src/content/reference/react/useDeferredValue.md +++ b/src/content/reference/react/useDeferredValue.md @@ -4,7 +4,7 @@ title: useDeferredValue -`useDeferredValue` is a React Hook that lets you defer updating a part of the UI. +`useDeferredValue` -- хук, с которым можно отложить обновление для части UI. ```js const deferredValue = useDeferredValue(value) @@ -16,11 +16,11 @@ const deferredValue = useDeferredValue(value) --- -## Reference {/*reference*/} +## Справочник {/*reference*/} ### `useDeferredValue(value)` {/*usedeferredvalue*/} -Call `useDeferredValue` at the top level of your component to get a deferred version of that value. +Чтобы сделать обновления значения отложенными, вызовите `useDeferredValue` с этим значением на верхнем уровне своего компонента: ```js import { useState, useDeferredValue } from 'react'; @@ -32,29 +32,29 @@ function SearchPage() { } ``` -[See more examples below.](#usage) +[См. другие примеры ниже.](#usage) -#### Parameters {/*parameters*/} +#### Параметры {/*parameters*/} -* `value`: The value you want to defer. It can have any type. +* `value`: Значение, обновление которого вы хотите откладывать. -#### Returns {/*returns*/} +#### Возвращаемое значение {/*returns*/} -During the initial render, the returned deferred value will be the same as the value you provided. During updates, React will first attempt a re-render with the old value (so it will return the old value), and then try another re-render in background with the new value (so it will return the updated value). +При первом рендеринге вызов вернёт то же значение, которое вы указали. Когда в следующих обновлениях значение изменится, вызов вернёт прошлое значение, но при этом React запустит дополнительный фоновый рендеринг, в котором вызов вернёт обновлённое значение. -#### Caveats {/*caveats*/} +#### Замечания {/*caveats*/} -- The values you pass to `useDeferredValue` should either be primitive values (like strings and numbers) or objects created outside of rendering. If you create a new object during rendering and immediately pass it to `useDeferredValue`, it will be different on every render, causing unnecessary background re-renders. +- Значения, которые вы передаёте в `useDeferredValue`, должны либо быть примитивного типа (как, например, строки или числа), либо должны создаваться **не** во время рендеринга. Если вы будете во время рендеринга каждый раз передавать в `useDeferredValue` свеже созданный объект, то так вы будете постоянно запускать ненужный фоновый рендеринг. -- When `useDeferredValue` receives a different value (compared with [`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is)), in addition to the current render (when it still uses the previous value), it schedules a re-render in the background with the new value. The background re-render is interruptible: if there's another update to the `value`, React will restart the background re-render from scratch. For example, if the user is typing into an input faster than a chart receiving its deferred value can re-render, the chart will only re-render after the user stops typing. +- Если `useDeferredValue` получит новое значение (сравнение будет через [`Object.is`](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Object/is)), то помимо текущего рендеринга (в котором хук вернёт старое значение), дополнительно в фоне запустится рендеринг для собственно нового значения. Но этот фоновый рендеринг может прерваться: если значение параметра `value` изменится ещё раз, то React перезапустит фоновый рендеринг заново. Например, если пользователь будет печатать быстрее, чем зависящий от ввода график будет успевать в фоне рендерить предыдущий ввод, то на экране график обновится, только когда пользователь перестанет печатать. -- `useDeferredValue` is integrated with [``.](/reference/react/Suspense) If the background update caused by a new value suspends the UI, the user will not see the fallback. They will see the old deferred value until the data loads. +- `useDeferredValue` интегрирован с [``.](/reference/react/Suspense) Если фоновое обновление для нового значения задержится, то вместо заглушки пользователь просто увидит старое значение, пока загружаются данные для фонового обновления. -- `useDeferredValue` does not by itself prevent extra network requests. +- Сам по себе `useDeferredValue` не защищает от лишних запросов в сеть. -- There is no fixed delay caused by `useDeferredValue` itself. As soon as React finishes the original re-render, React will immediately start working on the background re-render with the new deferred value. Any updates caused by events (like typing) will interrupt the background re-render and get prioritized over it. +- `useDeferredValue` не пытается отложить обновление на какое-то конкретное количество времени. Как только React закончит с текущим рендерингом, он сразу же запустит в фоне рендеринг нового отложенного значения. А любые обновления из-за внешних событий (пользователь печатает, например), будут просто более приоритетными, чем фоновый рендеринг, и прервут его. -- The background re-render caused by `useDeferredValue` does not fire Effects until it's committed to the screen. If the background re-render suspends, its Effects will run after the data loads and the UI updates. +- Эффекты фонового рендеринга, вызванного `useDeferredValue`, сработают, только когда React зафиксирует результат на экране. Если фоновый рендеринг запросит задержку, то эффекты сработают только после того, как данные загрузятся, а экран обновится. --- From fc789a25d42ea603a38455b2ee9786b4f32bfd91 Mon Sep 17 00:00:00 2001 From: Viacheslav Makarov <9768704+mekarthedev@users.noreply.github.com> Date: Sat, 29 Apr 2023 23:07:43 +0200 Subject: [PATCH 075/233] Translated first usage example of useDeferredValue --- .../reference/react/useDeferredValue.md | 56 +++++++++---------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/src/content/reference/react/useDeferredValue.md b/src/content/reference/react/useDeferredValue.md index ea18c49a8..86bdfe7ee 100644 --- a/src/content/reference/react/useDeferredValue.md +++ b/src/content/reference/react/useDeferredValue.md @@ -58,11 +58,11 @@ function SearchPage() { --- -## Usage {/*usage*/} +## Использование {/*usage*/} -### Showing stale content while fresh content is loading {/*showing-stale-content-while-fresh-content-is-loading*/} +### Отображение старых данных, пока загружаются новые {/*showing-stale-content-while-fresh-content-is-loading*/} -Call `useDeferredValue` at the top level of your component to defer updating some part of your UI. +Чтобы отложить обновление для части UI, вызовите `useDeferredValue` на верхнем уровне своего компонента: ```js [[1, 5, "query"], [2, 5, "deferredQuery"]] import { useState, useDeferredValue } from 'react'; @@ -74,25 +74,25 @@ function SearchPage() { } ``` -During the initial render, the deferred value will be the same as the value you provided. +При первом рендеринге отложенное значение будет равно значению, которое вы передадите. -During updates, the deferred value will "lag behind" the latest value. In particular, React will first re-render *without* updating the deferred value, and then try to re-render with the newly received value in background. +В следующих обновлениях отложенное значение будет как бы "отставать" от актуального значения. А именно: сначала React отрендерит компонент, *не обновляя* отложенное значение, а затем в фоне попытается отрендерить компонент с новым значением. -**Let's walk through an example to see when this is useful.** +**Разберём на примере, когда это может быть полезно.** -This example assumes you use one of Suspense-enabled data sources: +Предполагается, что данные в этом примере вы получаете через источники, которые поддерживают 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/advanced-features/react-18) -- Lazy-loading component code with [`lazy`](/reference/react/lazy) +- Запрашиваете данные с помощью поддерживающих Suspense фреймворков, как, например, [Relay](https://relay.dev/docs/guided-tour/rendering/loading-states/) или [Next.js](https://nextjs.org/docs/advanced-features/react-18). +- Лениво загружаете код компонентов с помощью [`lazy`](/reference/react/lazy). -[Learn more about Suspense and its limitations.](/reference/react/Suspense) +[Подробнее о Suspense и связанных с ним ограничениях.](/reference/react/Suspense) -In this example, the `SearchResults` component [suspends](/reference/react/Suspense#displaying-a-fallback-while-content-is-loading) while fetching the search results. Try typing `"a"`, waiting for the results, and then editing it to `"ab"`. The results for `"a"` get replaced by the loading fallback. +В этом примере компонент `SearchResults` [задерживается](/reference/react/Suspense#displaying-a-fallback-while-content-is-loading), т.к. отправляет поисковый запрос. Попробуйте ввести `"a"`, дождаться результатов поиска, и затем ввести `"ab"`. На месте результатов по запросу `"a"` ненадолго появится индикатор загрузки. @@ -120,10 +120,10 @@ export default function App() { return ( <> - Loading...

                        }> + Загрузка...

                      }> @@ -146,7 +146,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 (
                        @@ -284,7 +284,7 @@ input { margin: 10px; } -A common alternative UI pattern is to *defer* updating the list of results and to keep showing the previous results until the new results are ready. Call `useDeferredValue` to pass a deferred version of the query down: +Однако здесь можно применить другой частый паттерн в UI: *отложить* обновление списка результатов, продолжив показывать старые результаты, пока не подготовятся новые. Чтобы передавать в результаты поиска отложенную версию запроса, можно применить `useDeferredValue`: ```js {3,11} export default function App() { @@ -293,10 +293,10 @@ export default function App() { return ( <> - Loading...

                }> + Загрузка...

            }> @@ -304,9 +304,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` ещё некоторое время будет показывать старые результаты. -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 stale result list until the new results have loaded: +В изменённом примере ниже введите `"a"`, дождитесь загрузки результатов поиска, и затем измените запрос на `"ab"`. Обратите внимание, что теперь, пока загружаются новые результаты, вместо индикатора загрузки (заглушки Suspense) отображаются предыдущие результаты. @@ -335,10 +335,10 @@ export default function App() { return ( <> - Loading...

          }> + Загрузка...

        }> @@ -361,7 +361,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 (
          @@ -501,17 +501,17 @@ input { margin: 10px; } -#### How does deferring a value work under the hood? {/*how-does-deferring-a-value-work-under-the-hood*/} +#### Как работает отложенное обновление значения? {/*how-does-deferring-a-value-work-under-the-hood*/} -You can think of it as happening in two steps: +Для простоты удобно представлять, что обновление происходит в два этапа: -1. **First, React re-renders with the new `query` (`"ab"`) but with the old `deferredQuery` (still `"a")`.** The `deferredQuery` value, which you pass to the result list, is *deferred:* it "lags behind" the `query` value. +1. **Сначала React отрендерит компонент с новым запросом `"ab"` в `query`, но пока что с отложенным `"a"` в `deferredQuery`.** Значение в `deferredQuery`, которое вы передаёте в список результатов, является *отложенным:* оно "отстаёт" от значения `query`. -2. **In background, React tries to re-render with *both* `query` and `deferredQuery` updated to `"ab"`.** If this re-render completes, React will show it on the screen. However, if it suspends (the results for `"ab"` have not loaded yet), React will abandon this rendering attempt, and retry this re-render again after the data has loaded. The user will keep seeing the stale deferred value until the data is ready. +2. **Затем в фоне React попытается ещё раз отрендерить компонент, но уже с новым запросом `"ab"` и в `query`, и в `deferredQuery`.** Если этот рендеринг выполнится до конца, то React отобразит его результаты на экране. Но если рендеринг задержится (встанет в ожидании результатов для `"ab"`), то React эту конкретную попытку прервёт, а когда результаты загрузятся, попробует снова. Пока данные не загрузились, пользователю будет показываться старое отложенное значение. -The deferred "background" rendering is interruptible. For example, if you type into the input again, React will abandon it and restart with the new value. React will always use the latest provided value. +Отложенный фоновый рендеринг можно прервать. Если, например, продолжить печатать запрос, React прервёт фоновый рендеринг и перезапустит его уже с новым вводом. React всегда будет ориентироваться только на самое последнее переданное ему значение. -Note that there is still a network request per each keystroke. What's being deferred here is displaying results (until they're ready), not the network requests themselves. Even if the user continues typing, responses for each keystroke get cached, so pressing Backspace is instant and doesn't fetch again. +В этом примере важно обратить внимание, что запросы в сеть всё ещё отправляются по каждому нажатию на клавиатуре. Откладывается здесь именно обновление результатов на экране, а не отправка в сеть запроса поиска. Просто запрос по каждому нажатию кэшируется -- поэтому по удалению символа результат уже без запроса мгновенно берётся из кэша. From 39cd75b1a4e248efb74d7200691a59a5d190bceb Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Sun, 30 Apr 2023 04:39:33 +0300 Subject: [PATCH 076/233] Update render-and-commit.md --- src/content/learn/render-and-commit.md | 93 +++++++++++++------------- 1 file changed, 47 insertions(+), 46 deletions(-) diff --git a/src/content/learn/render-and-commit.md b/src/content/learn/render-and-commit.md index 84bf904cd..81e1ea245 100644 --- a/src/content/learn/render-and-commit.md +++ b/src/content/learn/render-and-commit.md @@ -1,27 +1,28 @@ --- -title: Render and Commit +title: Рендер и фиксация --- -Before your components are displayed on screen, they must be rendered by React. Understanding the steps in this process will help you think about how your code executes and explain its behavior. +Прежде чем ваши компоненты будут отображены на экране, они должны быть отрисованы React. Понимание этапов этого процесса поможет вам продумать, как выполняется ваш код, и объяснить его поведение + -* What rendering means in React -* When and why React renders a component -* The steps involved in displaying a component on screen -* Why rendering does not always produce a DOM update +* Что означает рендеринг в React +* Когда и почему React рендерит компонент +* Шаги, связанные с рендерингом компонента на экране. +* Почему рендеринг не всегда приводит к обновлению DOM -Imagine that your components are cooks in the kitchen, assembling tasty dishes from ingredients. In this scenario, React is the waiter who puts in requests from customers and brings them their orders. This process of requesting and serving UI has three steps: +Представьте, что ваши компоненты — это повара на кухне, собирающие вкусные блюда из ингредиентов. В этом сценарии React — это официант, который выполняет запросы клиентов и приносит им их заказы. Этот процесс запроса и подачи пользовательского интерфейса состоит из трех этапов: -1. **Triggering** a render (delivering the guest's order to the kitchen) -2. **Rendering** the component (preparing the order in the kitchen) -3. **Committing** to the DOM (placing the order on the table) +1. **Триггер** рендеринга (доставка заказа гостя на кухню) +2. **Рендеринг** компонента (подготовка заказа на кухне) +3. **Фиксация** в DOM (размещение заказа на столе) @@ -29,16 +30,16 @@ Imagine that your components are cooks in the kitchen, assembling tasty dishes f -## Step 1: Trigger a render {/*step-1-trigger-a-render*/} +## Step 1: Триггер рендера {/*step-1-trigger-a-render*/} -There are two reasons for a component to render: +Есть две причины для рендера компонента: -1. It's the component's **initial render.** -2. The component's (or one of its ancestors') **state has been updated.** +1. Это **первоначальный рендеринг компонента.** +2. Компонент (или один из его дочерних') **стейт был обновлён.** -### Initial render {/*initial-render*/} +### Начальный рендер {/*initial-render*/} -When your app starts, you need to trigger the initial render. Frameworks and sandboxes sometimes hide this code, but it's done by calling [`createRoot`](/reference/react-dom/client/createRoot) with the target DOM node, and then calling its `render` method with your component: +Когда ваше приложение запускается, вам необходимо вызвать начальный рендеринг. Фреймворки и песочницы иногда скрывают этот код, но он выполняется вызовом функции [`createRoot`](/reference/react-dom/client/createRoot) с целевым узлом DOM, а затем вызывая его метод `render` вашим компонентом: @@ -63,11 +64,11 @@ export default function Image() { -Try commenting out the `root.render()` call and see the component disappear! +Попробуйте закомментировать вызов `root.render()` и увидите, как компонент исчезнет! -### Re-renders when state updates {/*re-renders-when-state-updates*/} +### Ре-рендер, когда стейт обновляется {/*re-renders-when-state-updates*/} -Once the component has been initially rendered, you can trigger further renders by updating its state with the [`set` function.](/reference/react/useState#setstate) Updating your component's state automatically queues a render. (You can imagine these as a restaurant guest ordering tea, dessert, and all sorts of things after putting in their first order, depending on the state of their thirst or hunger.) +После того как компонент был первоначально отрендерен, вы можете инициировать последующие рендеры, обновляя его состояние с помощью функции [`set`](/reference/react/useState#setstate) Обновление стейта компонента автоматически ставит его в очередь на рендер. (Вы можете представить это как посетителя ресторана, который после первого заказа заказывает чай, десерт и всевозможные вещи, в зависимости от состояния жажды или голода). @@ -75,16 +76,16 @@ Once the component has been initially rendered, you can trigger further renders -## Step 2: React renders your components {/*step-2-react-renders-your-components*/} +## Step 2: React рендерит ваш компонент {/*step-2-react-renders-your-components*/} -After you trigger a render, React calls your components to figure out what to display on screen. **"Rendering" is React calling your components.** +После запуска рендера React вызывает ваши компоненты, чтобы определить, что отобразить на экране. **"Рендеринг" — это обращение React к вашим компонентам*. -* **On initial render,** React will call the root component. -* **For subsequent renders,** React will call the function component whose state update triggered the render. +* **На начальном рендере,** React вызовет корневой компонент. +* **Для последующих рендерингов** React будет вызывать функцию компонента, обновление стейта которого вызвало рендеринг. -This process is recursive: if the updated component returns some other component, React will render _that_ component next, and if that component also returns something, it will render _that_ component next, and so on. The process will continue until there are no more nested components and React knows exactly what should be displayed on screen. +Этот процесс рекурсивен: если обновленный компонент возвращает какой-то другой компонент, React будет рендерить _этот_ компонент следующим, и если этот компонент тоже что-то возвращает, он будет рендерить _этот_ компонент следующим, и так далее. Этот процесс будет продолжаться до тех пор, пока не останется вложенных компонентов и React не будет точно знать, что должно быть отображено на экране. -In the following example, React will call `Gallery()` and `Image()` several times: +В следующем примере React вызовет `Gallery()` и `Image()` несколько раз: @@ -124,36 +125,36 @@ img { margin: 0 10px 10px 0; } -* **During the initial render,** React will [create the DOM nodes](https://developer.mozilla.org/docs/Web/API/Document/createElement) for `
          `, `

          `, and three `` tags. -* **During a re-render,** React will calculate which of their properties, if any, have changed since the previous render. It won't do anything with that information until the next step, the commit phase. +* **На начальном рендере,** React [создаст DOM ноды](https://developer.mozilla.org/docs/Web/API/Document/createElement) для `
          `, `

          `, и трёзх `` тегов. +* **Во время повторного ре-рендеринга,** React вычислит, какие из их свойств, если таковые имеются, изменились с момента предыдущего рендеринга. Он ничего не будет делать с этой информацией до следующего шага, фазы фиксации. -Rendering must always be a [pure calculation](/learn/keeping-components-pure): +Рендеринг должен всегда быть [pure calculation](/learn/keeping-components-pure): -* **Same inputs, same output.** Given the same inputs, a component should always return the same JSX. (When someone orders a salad with tomatoes, they should not receive a salad with onions!) -* **It minds its own business.** It should not change any objects or variables that existed before rendering. (One order should not change anyone else's order.) +* **Одинаковые входные данные, одинаковые выходящие.** При одинаковых входящих данных компонент всегда должен возвращать один и тот же JSX. (Когда кто-то заказывает салат с помидорами, то он не должен получить салат с луком!) +* **Своими делами заниматься.** Не изменять объекты или переменные, существовавшие до рендеринга. (Один заказ не должен изменять чей-либо другой заказ). -Otherwise, you can encounter confusing bugs and unpredictable behavior as your codebase grows in complexity. When developing in "Strict Mode", React calls each component's function twice, which can help surface mistakes caused by impure functions. +В противном случае вы можете столкнуться с непонятными ошибками и непредсказуемым поведением по мере роста сложности вашей кодовой базы. При разработке в "строгом режиме" React вызывает функцию каждого компонента дважды, что может помочь выявить ошибки, вызванные нечистыми функциями. -#### Optimizing performance {/*optimizing-performance*/} +#### Оптимизируем производительность {/*optimizing-performance*/} -The default behavior of rendering all components nested within the updated component is not optimal for performance if the updated component is very high in the tree. If you run into a performance issue, there are several opt-in ways to solve it described in the [Performance](https://reactjs.org/docs/optimizing-performance.html) section. **Don't optimize prematurely!** +Поведение по умолчанию — рендеринг всех компонентов, вложенных в обновленный компонент, — не является оптимальным с точки зрения производительности, если обновляемый компонент находится очень высоко в дереве. Если вы столкнулись с проблемой производительности, есть несколько способов ее решения, описанных в разделе [Производительность](https://reactjs.org/docs/optimizing-performance.html). **Не оптимизируйте преждевременно!** -## Step 3: React commits changes to the DOM {/*step-3-react-commits-changes-to-the-dom*/} +## Step 3: React фиксирует изменения в DOM {/*step-3-react-commits-changes-to-the-dom*/} -After rendering (calling) your components, React will modify the DOM. +После рендеринга (вызова) ваших компонентов React модифицирует DOM. -* **For the initial render,** React will use the [`appendChild()`](https://developer.mozilla.org/docs/Web/API/Node/appendChild) DOM API to put all the DOM nodes it has created on screen. -* **For re-renders,** React will apply the minimal necessary operations (calculated while rendering!) to make the DOM match the latest rendering output. +* **На начальном рендере,** React использует [`appendChild()`](https://developer.mozilla.org/ru/docs/Web/API/Node/appendChild) DOM API, чтобы вставить все DOM ноды, которые он создал на экране. +* **Для ре-рендеров,** React будет применять минимально необходимые операции (вычисляемые во время рендеринга!), чтобы DOM соответствовал последнему выводу рендеринга. -**React only changes the DOM nodes if there's a difference between renders.** For example, here is a component that re-renders with different props passed from its parent every second. Notice how you can add some text into the ``, updating its `value`, but the text doesn't disappear when the component re-renders: +** React изменяет узлы DOM, только если есть разница между рендерами.** Например, вот компонент, который рендерится с разными пропсами, передаваемыми от родителя каждую секунду. Обратите внимание, как вы можете добавить некоторый текст в ``, обновляя его `значение`, но текст не исчезает при повторном рендеринге компонента: @@ -193,21 +194,21 @@ export default function App() { -This works because during this last step, React only updates the content of `

          ` with the new `time`. It sees that the `` appears in the JSX in the same place as last time, so React doesn't touch the ``—or its `value`! +Это работает, потому что в предыдущий раз, React обновил значение `

          ` с новым `time`. Он видит, что `` появляется в том же месте JSX, поэтому React не трогает ``— или его `value`! ## Epilogue: Browser paint {/*epilogue-browser-paint*/} -After rendering is done and React updated the DOM, the browser will repaint the screen. Although this process is known as "browser rendering", we'll refer to it as "painting" to avoid confusion throughout the docs. +После того как рендеринг завершен и React обновил DOM, браузер перерисовывает экран. Хотя этот процесс известен как "браузерный рендеринг", мы будем называть его "рисованием", чтобы избежать путаницы в документации. -* Any screen update in a React app happens in three steps: - 1. Trigger - 2. Render - 3. Commit -* You can use Strict Mode to find mistakes in your components -* React does not touch the DOM if the rendering result is the same as last time +* Любое обновление экрана в приложении React происходит в три этапа: + 1. Триггер + 2. Рендеринг + 3. Фиксация +* Вы можете использовать режим Strict Mode для поиска ошибок в ваших компонентах. +* React не трогает DOM, если результат рендеринга такой же, как и в прошлый раз. From ccba4e07cb92e4f311a09b07c1e8b7933e628651 Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Sun, 30 Apr 2023 04:44:14 +0300 Subject: [PATCH 077/233] Update render-and-commit.md --- src/content/learn/render-and-commit.md | 1 - 1 file changed, 1 deletion(-) diff --git a/src/content/learn/render-and-commit.md b/src/content/learn/render-and-commit.md index 81e1ea245..4c7e069da 100644 --- a/src/content/learn/render-and-commit.md +++ b/src/content/learn/render-and-commit.md @@ -6,7 +6,6 @@ title: Рендер и фиксация Прежде чем ваши компоненты будут отображены на экране, они должны быть отрисованы React. Понимание этапов этого процесса поможет вам продумать, как выполняется ваш код, и объяснить его поведение - From 3e824825415e1fdd0a7f2aa32c3bee4efd93aa8e Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Sun, 30 Apr 2023 04:56:41 +0300 Subject: [PATCH 078/233] Update render-and-commit.md --- src/content/learn/render-and-commit.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/content/learn/render-and-commit.md b/src/content/learn/render-and-commit.md index 4c7e069da..41204c643 100644 --- a/src/content/learn/render-and-commit.md +++ b/src/content/learn/render-and-commit.md @@ -10,10 +10,10 @@ title: Рендер и фиксация -* Что означает рендеринг в React -* Когда и почему React рендерит компонент +* Что означает рендеринг в React. +* Когда и почему React рендерит компонент. * Шаги, связанные с рендерингом компонента на экране. -* Почему рендеринг не всегда приводит к обновлению DOM +* Почему рендеринг не всегда приводит к обновлению DOM. From e2340fa3c7e145b88e31f55206fbf176bb6e8163 Mon Sep 17 00:00:00 2001 From: Viacheslav Makarov <9768704+mekarthedev@users.noreply.github.com> Date: Sun, 30 Apr 2023 14:52:10 +0200 Subject: [PATCH 079/233] Fixed wording for nextId++ --- src/content/reference/react/useId.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/content/reference/react/useId.md b/src/content/reference/react/useId.md index a05d3f659..5457292d6 100644 --- a/src/content/reference/react/useId.md +++ b/src/content/reference/react/useId.md @@ -42,7 +42,7 @@ function PasswordField() { #### Замечания {/*caveats*/} -* `useId` -- это хук. Поэтому его можно вызывать только **на верхнем уровне кода вашего компонента** или хука. Его нельзя вызывать внутри циклов и условий. Если это всё же для чего-то нужно, выделите этот вызов в отдельный компонент, который затем можно рендерить по условию или в цикле. +* `useId` -- это хук, поэтому его нужно вызывать только **на верхнем уровне вашего компонента** или хука. Его нельзя вызывать внутри циклов и условий. Если это всё же для чего-то нужно, выделите этот вызов в отдельный компонент, который затем можно рендерить по условию или в цикле. * `useId` **не должен использоваться для создания ключей** в списках. [Ключи должны выбираться на основе данных.](/learn/rendering-lists#where-to-get-your-key) @@ -175,7 +175,7 @@ input { margin: 5px; } #### Чем `useId` лучше обычного инкрементируемого счётчика? {/*why-is-useid-better-than-an-incrementing-counter*/} -Возможно вы задаётесь вопросом, почему лучше использовать `useId`, а не просто постоянно увеличивать некий глобальный счётчик -- наподобие `nextId++`. +Возможно, вы задаётесь вопросом, почему для получения нового идентификатора лучше использовать `useId`, а не увеличивать постоянно некий глобальный счётчик -- `nextId++`. Главное преимущество `useId` в том, что React гарантирует его корректную работу с [серверным рендерингом](/reference/react-dom/server). В процессе серверного рендеринга ваши компоненты создают HTML, к которому затем на клиенте при [гидратации](/reference/react-dom/client/hydrateRoot) подключаются ваши обработчики событий. Чтобы гидратация сработала правильно, клиентский вывод должен совпасть с полученным от сервера HTML. From 3b73bf1993eabd2788f00b94bfffb165b1796343 Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Sun, 30 Apr 2023 16:14:18 +0300 Subject: [PATCH 080/233] Update src/content/learn/render-and-commit.md Co-authored-by: Fedya Petrakov --- src/content/learn/render-and-commit.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/render-and-commit.md b/src/content/learn/render-and-commit.md index 41204c643..9f362ffbd 100644 --- a/src/content/learn/render-and-commit.md +++ b/src/content/learn/render-and-commit.md @@ -4,7 +4,7 @@ title: Рендер и фиксация -Прежде чем ваши компоненты будут отображены на экране, они должны быть отрисованы React. Понимание этапов этого процесса поможет вам продумать, как выполняется ваш код, и объяснить его поведение +Прежде чем ваши компоненты появятся на экране, они должны быть отрисованы React. Понимая этапы этого процесса, вам будет проще судить о том, как исполняется ваш код, и объяснить его поведение From e175dc7b93bac1e6be0641c35c548067d987e0b9 Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Sun, 30 Apr 2023 16:14:29 +0300 Subject: [PATCH 081/233] Update src/content/learn/render-and-commit.md Co-authored-by: Fedya Petrakov --- src/content/learn/render-and-commit.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/render-and-commit.md b/src/content/learn/render-and-commit.md index 9f362ffbd..155fa607d 100644 --- a/src/content/learn/render-and-commit.md +++ b/src/content/learn/render-and-commit.md @@ -12,7 +12,7 @@ title: Рендер и фиксация * Что означает рендеринг в React. * Когда и почему React рендерит компонент. -* Шаги, связанные с рендерингом компонента на экране. +* Этапы отображения компонента на экране. * Почему рендеринг не всегда приводит к обновлению DOM. From 2b6af95e0e079fcc7674f36b7bfc900c9f018179 Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Sun, 30 Apr 2023 16:14:36 +0300 Subject: [PATCH 082/233] Update src/content/learn/render-and-commit.md Co-authored-by: Fedya Petrakov --- src/content/learn/render-and-commit.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/render-and-commit.md b/src/content/learn/render-and-commit.md index 155fa607d..c8af62871 100644 --- a/src/content/learn/render-and-commit.md +++ b/src/content/learn/render-and-commit.md @@ -17,7 +17,7 @@ title: Рендер и фиксация -Представьте, что ваши компоненты — это повара на кухне, собирающие вкусные блюда из ингредиентов. В этом сценарии React — это официант, который выполняет запросы клиентов и приносит им их заказы. Этот процесс запроса и подачи пользовательского интерфейса состоит из трех этапов: +Представьте, что ваши компоненты — это повара на кухне, которые составляют вкусные блюда из ингредиентов. Тогда React — это официант, который передает запросы клиентов, а затем подает им их блюда. Этот процесс запроса и подачи пользовательского интерфейса состоит из трех этапов: 1. **Триггер** рендеринга (доставка заказа гостя на кухню) 2. **Рендеринг** компонента (подготовка заказа на кухне) From a061128f2de5043476aca365386dcea4d2e6e6c8 Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Sun, 30 Apr 2023 16:14:45 +0300 Subject: [PATCH 083/233] Update src/content/learn/render-and-commit.md Co-authored-by: Fedya Petrakov --- src/content/learn/render-and-commit.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/render-and-commit.md b/src/content/learn/render-and-commit.md index c8af62871..55ae63e83 100644 --- a/src/content/learn/render-and-commit.md +++ b/src/content/learn/render-and-commit.md @@ -19,7 +19,7 @@ title: Рендер и фиксация Представьте, что ваши компоненты — это повара на кухне, которые составляют вкусные блюда из ингредиентов. Тогда React — это официант, который передает запросы клиентов, а затем подает им их блюда. Этот процесс запроса и подачи пользовательского интерфейса состоит из трех этапов: -1. **Триггер** рендеринга (доставка заказа гостя на кухню) +1. **Триггер** рендеринга (передача заказа гостя на кухню) 2. **Рендеринг** компонента (подготовка заказа на кухне) 3. **Фиксация** в DOM (размещение заказа на столе) From e6331381ef7ac764b8dee4f031f5c6a63b48c9b8 Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Sun, 30 Apr 2023 16:14:52 +0300 Subject: [PATCH 084/233] Update src/content/learn/render-and-commit.md Co-authored-by: Fedya Petrakov --- src/content/learn/render-and-commit.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/render-and-commit.md b/src/content/learn/render-and-commit.md index 55ae63e83..8eb58b161 100644 --- a/src/content/learn/render-and-commit.md +++ b/src/content/learn/render-and-commit.md @@ -31,7 +31,7 @@ title: Рендер и фиксация ## Step 1: Триггер рендера {/*step-1-trigger-a-render*/} -Есть две причины для рендера компонента: +Рендер компонента происходит по двум причинам: 1. Это **первоначальный рендеринг компонента.** 2. Компонент (или один из его дочерних') **стейт был обновлён.** From 5ad7dc224ac1c3d888a6664d1e8e40a9eae9d614 Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Sun, 30 Apr 2023 16:14:58 +0300 Subject: [PATCH 085/233] Update src/content/learn/render-and-commit.md Co-authored-by: Fedya Petrakov --- src/content/learn/render-and-commit.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/render-and-commit.md b/src/content/learn/render-and-commit.md index 8eb58b161..ce346c31e 100644 --- a/src/content/learn/render-and-commit.md +++ b/src/content/learn/render-and-commit.md @@ -34,7 +34,7 @@ title: Рендер и фиксация Рендер компонента происходит по двум причинам: 1. Это **первоначальный рендеринг компонента.** -2. Компонент (или один из его дочерних') **стейт был обновлён.** +2. Его **стейт** (или стейт его родителя) **был обновлён.** ### Начальный рендер {/*initial-render*/} From 708e60aebc81b5cf1eda2a789aa9ed47ab3a4551 Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Sun, 30 Apr 2023 16:15:13 +0300 Subject: [PATCH 086/233] Update src/content/learn/render-and-commit.md Co-authored-by: Fedya Petrakov --- src/content/learn/render-and-commit.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/render-and-commit.md b/src/content/learn/render-and-commit.md index ce346c31e..f8addf497 100644 --- a/src/content/learn/render-and-commit.md +++ b/src/content/learn/render-and-commit.md @@ -21,7 +21,7 @@ title: Рендер и фиксация 1. **Триггер** рендеринга (передача заказа гостя на кухню) 2. **Рендеринг** компонента (подготовка заказа на кухне) -3. **Фиксация** в DOM (размещение заказа на столе) +3. **Фиксация** в DOM (подача блюда на стол) From e3b3584375e6eda21256fac2ae4850988e0d35c7 Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Sun, 30 Apr 2023 16:15:37 +0300 Subject: [PATCH 087/233] Update src/content/learn/render-and-commit.md Co-authored-by: Fedya Petrakov --- src/content/learn/render-and-commit.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/render-and-commit.md b/src/content/learn/render-and-commit.md index f8addf497..b43ac5907 100644 --- a/src/content/learn/render-and-commit.md +++ b/src/content/learn/render-and-commit.md @@ -33,7 +33,7 @@ title: Рендер и фиксация Рендер компонента происходит по двум причинам: -1. Это **первоначальный рендеринг компонента.** +1. Это его **первоначальный рендеринг.** 2. Его **стейт** (или стейт его родителя) **был обновлён.** ### Начальный рендер {/*initial-render*/} From c31ad6da263f45c5068348a5f2571d8b55c485da Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Sun, 30 Apr 2023 16:15:56 +0300 Subject: [PATCH 088/233] Update src/content/learn/render-and-commit.md Co-authored-by: Fedya Petrakov --- src/content/learn/render-and-commit.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/render-and-commit.md b/src/content/learn/render-and-commit.md index b43ac5907..b85e4949d 100644 --- a/src/content/learn/render-and-commit.md +++ b/src/content/learn/render-and-commit.md @@ -20,7 +20,7 @@ title: Рендер и фиксация Представьте, что ваши компоненты — это повара на кухне, которые составляют вкусные блюда из ингредиентов. Тогда React — это официант, который передает запросы клиентов, а затем подает им их блюда. Этот процесс запроса и подачи пользовательского интерфейса состоит из трех этапов: 1. **Триггер** рендеринга (передача заказа гостя на кухню) -2. **Рендеринг** компонента (подготовка заказа на кухне) +2. **Рендеринг** компонента (приготовление заказа на кухне) 3. **Фиксация** в DOM (подача блюда на стол) From 006a1c619b3db2fbde62df5646083df70944513d Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Sun, 30 Apr 2023 16:17:17 +0300 Subject: [PATCH 089/233] Update render-and-commit.md --- src/content/learn/render-and-commit.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/render-and-commit.md b/src/content/learn/render-and-commit.md index b85e4949d..dc44fa9a8 100644 --- a/src/content/learn/render-and-commit.md +++ b/src/content/learn/render-and-commit.md @@ -33,7 +33,7 @@ title: Рендер и фиксация Рендер компонента происходит по двум причинам: -1. Это его **первоначальный рендеринг.** +1. Это его **начальный рендеринг.** 2. Его **стейт** (или стейт его родителя) **был обновлён.** ### Начальный рендер {/*initial-render*/} From ac724bc52360c370a596a9781dab2352440c86d1 Mon Sep 17 00:00:00 2001 From: Viacheslav Makarov <9768704+mekarthedev@users.noreply.github.com> Date: Sun, 30 Apr 2023 15:25:31 +0200 Subject: [PATCH 090/233] For intro, use 'summary' style instead of 'definition' style --- src/content/reference/react/useId.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/reference/react/useId.md b/src/content/reference/react/useId.md index 5457292d6..1444c1d9c 100644 --- a/src/content/reference/react/useId.md +++ b/src/content/reference/react/useId.md @@ -4,7 +4,7 @@ title: useId -`useId` -- хук для генерации уникальных идентификаторов, которые можно использовать, например, в атрибутах доступности. +Хук `useId` позволяет создавать уникальные идентификаторы, которые затем можно использовать, например, в атрибутах доступности. ```js const id = useId() From 21948f82c6e1d3f746b4a0335edab9ebefacb71a Mon Sep 17 00:00:00 2001 From: Viacheslav Makarov <9768704+mekarthedev@users.noreply.github.com> Date: Sun, 30 Apr 2023 16:11:51 +0200 Subject: [PATCH 091/233] Re-word intro in 'summary' style instead of 'definition' style --- src/content/reference/react/useDeferredValue.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/reference/react/useDeferredValue.md b/src/content/reference/react/useDeferredValue.md index 86bdfe7ee..006c7c03c 100644 --- a/src/content/reference/react/useDeferredValue.md +++ b/src/content/reference/react/useDeferredValue.md @@ -4,7 +4,7 @@ title: useDeferredValue -`useDeferredValue` -- хук, с которым можно отложить обновление для части UI. +Хук `useDeferredValue` позволяет откладывать обновление для части UI. ```js const deferredValue = useDeferredValue(value) From e901c035aebdc5f1ad05d88d9b555e9db70aa840 Mon Sep 17 00:00:00 2001 From: Maxim Tereshko Date: Sun, 30 Apr 2023 17:55:20 +0200 Subject: [PATCH 092/233] chore: added russian translation --- src/content/learn/react-developer-tools.md | 46 ++++++++++++---------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/src/content/learn/react-developer-tools.md b/src/content/learn/react-developer-tools.md index 89208a6bb..dd20c008e 100644 --- a/src/content/learn/react-developer-tools.md +++ b/src/content/learn/react-developer-tools.md @@ -4,30 +4,31 @@ title: React Developer Tools -Use React Developer Tools to inspect React [components](/learn/your-first-component), edit [props](/learn/passing-props-to-a-component) and [state](/learn/state-a-components-memory), and identify performance problems. +Используйте React Developer Tools для инспекции [компонентов](/learn/your-first-component) React, редактирования [пропсов](/learn/passing-props-to-a-component) и [состояния](/learn/state-a-components-memory), а также для выявления проблем с производительностью. -* How to install React Developer Tools +* Как установить React Developer Tools -## Browser extension {/*browser-extension*/} +## Расширение для браузера {/*browser-extension*/} -The easiest way to debug websites built with React is to install the React Developer Tools browser extension. It is available for several popular browsers: +Самым простым способом отладки сайтов, созданных с использованием React, является установка браузерного расширения React Developer Tools. Оно доступно для нескольких популярных браузеров. -* [Install for **Chrome**](https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi?hl=en) -* [Install for **Firefox**](https://addons.mozilla.org/en-US/firefox/addon/react-devtools/) -* [Install for **Edge**](https://microsoftedge.microsoft.com/addons/detail/react-developer-tools/gpphkfbcpidddadnkolkpfckpihlkkil) +* [Установить для **Chrome**](https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi?hl=ru) +* [Установить для **Firefox**](https://addons.mozilla.org/ru/firefox/addon/react-devtools/) +* [Установить для **Edge**](https://microsoftedge.microsoft.com/addons/detail/react-developer-tools/gpphkfbcpidddadnkolkpfckpihlkkil) -Now, if you visit a website **built with React,** you will see the _Components_ and _Profiler_ panels. +Если вы откроете сайт, созданный с использованием React, вы увидите панели _Components_ и _Profiler_. -![React Developer Tools extension](/images/docs/react-devtools-extension.png) +![Расширение React Developer Tools](/images/docs/react-devtools-extension.png) + +### Safari и другие браузеры {/*safari-and-other-browsers*/} +Для других браузеров, таких как Safari, необходимо установить npm пакет [`react-devtools`](https://www.npmjs.com/package/react-devtools): -### Safari and other browsers {/*safari-and-other-browsers*/} -For other browsers (for example, Safari), install the [`react-devtools`](https://www.npmjs.com/package/react-devtools) npm package: ```bash # Yarn yarn global add react-devtools @@ -36,26 +37,28 @@ yarn global add react-devtools npm install -g react-devtools ``` -Next open the developer tools from the terminal: +Затем откройте инструменты разработчика из терминала: + ```bash react-devtools ``` -Then connect your website by adding the following ` ``` -Reload your website in the browser now to view it in developer tools. +Перезагрузите ваш сайт, чтобы просмотреть его в инструментах разработчика. ![React Developer Tools standalone](/images/docs/react-devtools-standalone.png) -## Mobile (React Native) {/*mobile-react-native*/} -React Developer Tools can be used to inspect apps built with [React Native](https://reactnative.dev/) as well. +## Мобильные устройства (React Native) {/*mobile-react-native*/} +React Developer Tools также может использоваться для отладки приложений, созданных с помощью [React Native](https://reactnative.dev/). + +Самый простой способ использования React Developer Tools - установить их глобально: -The easiest way to use React Developer Tools is to install it globally: ```bash # Yarn yarn global add react-devtools @@ -64,13 +67,14 @@ yarn global add react-devtools npm install -g react-devtools ``` -Next open the developer tools from the terminal. +Откройте инструменты разработчика в терминале. + ```bash react-devtools ``` -It should connect to any local React Native app that's running. +Он подключится к любому локальному приложению React Native, которое запущено. -> Try reloading the app if developer tools doesn't connect after a few seconds. +> Попробуйте перезагрузить приложение, если инструменты разработчика не подключатся через несколько секунд. -[Learn more about debugging React Native.](https://reactnative.dev/docs/debugging) +[Узнайте больше о отладке React Native.](https://reactnative.dev/docs/debugging) From 4940267c332ff30f5cba25241c88dd26710d4f77 Mon Sep 17 00:00:00 2001 From: Maxim Tereshko Date: Sun, 30 Apr 2023 17:56:19 +0200 Subject: [PATCH 093/233] fix: fixed spaces --- src/content/learn/react-developer-tools.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/content/learn/react-developer-tools.md b/src/content/learn/react-developer-tools.md index dd20c008e..f13c90567 100644 --- a/src/content/learn/react-developer-tools.md +++ b/src/content/learn/react-developer-tools.md @@ -38,7 +38,6 @@ npm install -g react-devtools ``` Затем откройте инструменты разработчика из терминала: - ```bash react-devtools ``` @@ -56,7 +55,6 @@ react-devtools ## Мобильные устройства (React Native) {/*mobile-react-native*/} React Developer Tools также может использоваться для отладки приложений, созданных с помощью [React Native](https://reactnative.dev/). - Самый простой способ использования React Developer Tools - установить их глобально: ```bash @@ -68,7 +66,6 @@ npm install -g react-devtools ``` Откройте инструменты разработчика в терминале. - ```bash react-devtools ``` From 1e7fc4315475ae905f96c52910d87bd555757bf2 Mon Sep 17 00:00:00 2001 From: Viacheslav Makarov <9768704+mekarthedev@users.noreply.github.com> Date: Sun, 30 Apr 2023 17:57:24 +0200 Subject: [PATCH 094/233] Translated more usage of useDeferredValue --- src/content/reference/react/useDeferredValue.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/content/reference/react/useDeferredValue.md b/src/content/reference/react/useDeferredValue.md index 006c7c03c..44c290e54 100644 --- a/src/content/reference/react/useDeferredValue.md +++ b/src/content/reference/react/useDeferredValue.md @@ -517,9 +517,9 @@ input { margin: 10px; } --- -### Indicating that the content is stale {/*indicating-that-the-content-is-stale*/} +### Подсветка неактуальных данных {/*indicating-that-the-content-is-stale*/} -In the example above, there is no indication that the result list for the latest query is still loading. This can be confusing to the user if the new results take a while to load. To make it more obvious to the user that the result list does not match the latest query, you can add a visual indication when the stale result list is displayed: +В предыдущем примере в списке последних результатов никак не обозначалось, что результаты по новому запросу всё ещё загружаются. Такой интерфейс может сбить с толку, особенно если новые результаты будут загружаться долго. Решить проблему можно, добавив визуальную индикацию для случая, когда отображаемый список результатов больше не актуален и не соответствует последнему запросу: ```js {2}
          ``` -With this change, as soon as you start typing, the stale result list gets slightly dimmed until the new result list loads. You can also add a CSS transition to delay dimming so that it feels gradual, like in the example below: +Благодаря этим изменениям, когда вы начнёте набирать новый запрос, список старых результатов потускнеет, пока не загрузится новый список. Вы даже можете добавить анимированный переход с задержкой, чтобы визуально "устаревание" ощущалось постепенным. Например: @@ -559,10 +559,10 @@ export default function App() { return ( <> - Loading...

          }> + Загрузка...

          }>
          No matches for "{query}"

          ; + return

          По запросу "{query}" ничего не найдено

          ; } return (
            From ae676dffb59a21b932570870ee51115f12ec4596 Mon Sep 17 00:00:00 2001 From: Maxim Tereshko Date: Sun, 30 Apr 2023 18:09:30 +0200 Subject: [PATCH 095/233] chore: added russian translation --- src/content/reference/react-dom/index.md | 31 ++++++++++++------------ 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/src/content/reference/react-dom/index.md b/src/content/reference/react-dom/index.md index 5b2648c18..47dc51f6e 100644 --- a/src/content/reference/react-dom/index.md +++ b/src/content/reference/react-dom/index.md @@ -1,10 +1,10 @@ --- -title: React DOM APIs +title: API React DOM --- -The `react-dom` package contains methods that are only supported for the web applications (which run in the browser DOM environment). They are not supported for React Native. +Пакет `react-dom` содержит методы, которые поддерживаются только для веб-приложений (которые работают в DOM среде браузера). Они не поддерживаются для React Native. @@ -12,32 +12,31 @@ The `react-dom` package contains methods that are only supported for the web app ## APIs {/*apis*/} -These APIs can be imported from your components. They are rarely used: +Эти API могут быть импортированы из ваших компонентов. Они используются редко: -* [`createPortal`](/reference/react-dom/createPortal) lets you render child components in a different part of the DOM tree. -* [`flushSync`](/reference/react-dom/flushSync) lets you force React to flush a state update and update the DOM synchronously. +* [`createPortal`](/reference/react-dom/createPortal) позволяет рендерить дочерние компоненты в другой части DOM-дерева. +* [`flushSync`](/reference/react-dom/flushSync) позволяет принудительно вынудить React обновить состояние и синхронно обновить DOM. --- -## Entry points {/*entry-points*/} +## Точки входа {/*entry-points*/} -The `react-dom` package provides two additional entry points: +Пакет `react-dom` предоставляет две дополнительные точки входа: -* [`react-dom/client`](/reference/react-dom/client) contains APIs to render React components on the client (in the browser). -* [`react-dom/server`](/reference/react-dom/server) contains APIs to render React components on the server. +* [`react-dom/client`](/reference/react-dom/client) содержит API для рендеринга компонентов React на стороне клиента (в браузере). +* [`react-dom/server`](/reference/react-dom/server) содержит API для рендеринга компонентов React на сервере. --- -## Deprecated APIs {/*deprecated-apis*/} +## Устаревшие API {/*deprecated-apis*/} -These APIs will be removed in a future major version of React. +Эти API будут удалены в одной из следующих версий React. -* [`findDOMNode`](/reference/react-dom/findDOMNode) finds the closest DOM node corresponding to a class component instance. -* [`hydrate`](/reference/react-dom/hydrate) mounts a tree into the DOM created from server HTML. Deprecated in favor of [`hydrateRoot`](/reference/react-dom/client/hydrateRoot). -* [`render`](/reference/react-dom/render) mounts a tree into the DOM. Deprecated in favor of [`createRoot`](/reference/react-dom/client/createRoot). -* [`unmountComponentAtNode`](/reference/react-dom/unmountComponentAtNode) unmounts a tree from the DOM. Deprecated in favor of [`root.unmount()`.](/reference/react-dom/client/createRoot#root-unmount) - +* [`findDOMNode`](/reference/react-dom/findDOMNode) находит ближайший DOM-узел, соответствующий экземпляру классового компонента. +* [`hydrate`](/reference/react-dom/hydrate) монтирует дерево в DOM, созданное из HTML на сервере. Устарел в пользу [`hydrateRoot`](/reference/react-dom/client/hydrateRoot). +* [`render`](/reference/react-dom/render) монтирует дерево в DOM. Устарел в пользу [`createRoot`](/reference/react-dom/client/createRoot). +* [`unmountComponentAtNode`](/reference/react-dom/unmountComponentAtNode) размонтирует дерево из DOM. Устарел в пользу [`root.unmount()`](/reference/react-dom/client/createRoot#root-unmount). \ No newline at end of file From 560eeaac6fec9250135019727c2696b25ae86ce8 Mon Sep 17 00:00:00 2001 From: Konstantin Arabei Date: Mon, 1 May 2023 01:27:23 +0700 Subject: [PATCH 096/233] fixes after review --- src/content/learn/your-first-component.md | 32 +++++++++++------------ 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/content/learn/your-first-component.md b/src/content/learn/your-first-component.md index d0662e2b4..bc5992db9 100644 --- a/src/content/learn/your-first-component.md +++ b/src/content/learn/your-first-component.md @@ -87,13 +87,13 @@ img { height: 200px; } -React-компоненты — это обычные фукнции JavaScript, но **их имена должны начинаться с заглавной буквы**, иначе они не будут работать! +React-компоненты — это обычные JavaScript функции, но **их имена должны начинаться с заглавной буквы**, иначе они не будут работать! ### Шаг 3: Добавить разметку {/*step-3-add-markup*/} -Компонент возвращает тег `` с атрибутами `src` и `alt`. `` выглядит как HTML, но на самом деле это JavaScript! Этот синтаксис называется [JSX](/learn/writing-markup-with-jsx), и он позволяет вам вставлять разметку внутрь JavaScript. +Компонент возвращает тег `` с атрибутами `src` и `alt`. `` выглядит как HTML, но на самом деле под капотом это JavaScript! Этот синтаксис называется [JSX](/learn/writing-markup-with-jsx), и он позволяет вам вставлять разметку в JavaScript. Оператор `return` можно записать в одну строку, как в этом компоненте: @@ -101,7 +101,7 @@ React-компоненты — это обычные фукнции JavaScript, return Кэтрин Джонсон; ``` -Но если вся ваша разметка не находится на той же строке, что и ключевое слово `return`, вы должны обернуть её в пару скобок: +Но если вся ваша разметка не находится на той же строке, что и ключевое слово `return`, то вы должны обернуть её в пару скобок: ```js return ( @@ -151,7 +151,7 @@ img { margin: 0 10px 10px 0; height: 90px; } -### Что видит барузер {/*what-the-browser-sees*/} +### Что видит браузер {/*what-the-browser-sees*/} Обратите внимание на разницу в регистре: @@ -216,16 +216,16 @@ function Profile() { [Фреймворки на основе React](/learn/start-a-new-react-project) пошли ещё дальше. Вместо того, чтобы использовать пустой файл HTML и позволять React "захватывать" управление страницей с помощью JavaScript, они *также* автоматически генерируют HTML из ваших React-компонентов. Это позволяет вашему приложению показывать часть контента до того, как загрузится JavaScript код. -Тем не менее, многие веб-сайты используют React только для [добавления интерактивности на существующие HTML-страницы.](/learn/add-react-to-an-existing-project#using-react-for-a-part-of-your-existing-page) У них есть множество корневых компонентов вместо одного для всей страницы. Вы можете использовать столько функциональности React, сколько вам нужно. +Тем не менее, многие веб-сайты используют React только для [добавления интерактивности на существующие HTML-страницы.](/learn/add-react-to-an-existing-project#using-react-for-a-part-of-your-existing-page) У них есть множество корневых компонентов вместо одного для всей страницы. Вы можете брать от React столько, сколько вам нужно. -Вы только что познакомились с React! Давайте вспомним некоторые ключевые моменты. +Вы только что познакомились с React! Давайте повторим некоторые ключевые моменты. * React позволяет вам создавать компоненты, **переиспользуемые элементы UI для вашего приложения.** -* В React-приложении каждый элемент UI является компонентом. +* В React-приложении каждый элемент UI это компонент. * Компоненты React — это обычные функции JavaScript, за исключением того, что: 1. Их имена всегда начинаются с заглавной буквы. @@ -285,17 +285,17 @@ img { height: 181px; } -Возможно, вы задаётесь вопросом, почему написание только `export` недостаточно для исправления этого примера. Вы можете узнать разницу между `export` и `export default` в разделе [Импорт и Экспорт компонентов.](/learn/importing-and-exporting-components) +Возможно, вы задаётесь вопросом, почему одного только написания `export` недостаточно, чтобы исправить этот пример. Вы можете узнать разницу между `export` и `export default` в разделе [Импорт и Экспорт компонентов.](/learn/importing-and-exporting-components) -#### Исправьте возвращаемое выражение {/*fix-the-return-statement*/} +#### Исправьте оператор return {/*fix-the-return-statement*/} -Что-то не так с оператором `return`. Вы можете это исправить? +Что-то не так с оператором `return`. Сможете его исправить? -При попытке исправить это вы можете получить ошибку "Unexpected token". В этом случае убедитесь, что точка с запятой находится *после* закрывающей скобки. Оставление точки с запятой внутри `return ( )` приведёт к ошибке. +При попытке исправить оператор вы можете получить ошибку "Unexpected token". В этом случае убедитесь, что точка с запятой находится *после* закрывающей скобки. Оставив точку с запятой внутри `return ( )`, вы вызовите ошибку. @@ -317,7 +317,7 @@ img { height: 180px; } -Вы можете исправить этот компонент, записав возвращаемое выражение в одну строку, например так: +Вы можете исправить этот компонент, записав оператор `return` в одну строку, вот так: @@ -356,9 +356,9 @@ img { height: 180px; } -#### Найти ошибку {/*spot-the-mistake*/} +#### Найдите ошибку {/*spot-the-mistake*/} -Что-то не так с объявлением и использованием компонента `Profile`. Можете найти ошибку? (Попробуйте вспомнить, как React отличает компоненты от обычных тегов HTML!) +Что-то не так с тем, как объявлен и использован компонента `Profile`. Сможете найти ошибку? (Попробуйте вспомнить, как React отличает компоненты от обычных тегов HTML!) @@ -394,7 +394,7 @@ img { margin: 0 10px 10px 0; height: 90px; } Имена React-компонентов должны начинаться с заглавной буквы. -Измените `function profile()` на `function Profile()`, а затем измените каждый `` на ``: +Замените `function profile()` на `function Profile()`, а затем каждый `` на ``: @@ -430,7 +430,7 @@ img { margin: 0 10px 10px 0; } #### Ваш компонент {/*your-own-component*/} -Напишите компонент с нуля. Вы можете дать ему любое допустимое имя и возвращать любую разметку. Если ничего не приходит на ум, то вы можете написать компонент `Congratulations`, который отображает `

            Хорошая работа!

            `. Не забудьте экспортировать компонент! +Напишите компонент с нуля. Вы можете дать ему любое допустимое имя и вернуть любую разметку. Если ничего не приходит на ум, то вы можете написать компонент `Congratulations`, который отображает заголовок `

            Хорошая работа!

            `. Не забудьте экспортировать компонент! From 372315606e214e8b9ace096e7c7553cc2a9b3678 Mon Sep 17 00:00:00 2001 From: Konstantin Arabei Date: Mon, 1 May 2023 16:02:16 +0700 Subject: [PATCH 097/233] fixes after review --- src/content/learn/your-first-component.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/content/learn/your-first-component.md b/src/content/learn/your-first-component.md index bc5992db9..23c0eb957 100644 --- a/src/content/learn/your-first-component.md +++ b/src/content/learn/your-first-component.md @@ -31,11 +31,11 @@ title: Ваш первый компонент
        ``` -Эта разметка представляет эту статью как `
        `, её заголовок как `

        ` и (сокращённое) оглавление как упорядоченный список `
          `. Такая разметка, в сочетании с CSS для стилизации и JavaScript для создания интерактивности, лежит в основе каждой боковой панели, аватара, модального окна, выпадающего меню — каждой части UI, которую вы видите в интернете. +Разметка выше представляет эту статью как `
          `, её заголовок как `

          ` и (сокращённое) оглавление как упорядоченный список `
            `. Такая разметка, в сочетании с CSS для стилизации и JavaScript для создания интерактивности, кроется в каждой боковой панели, аватаре, модальном окне, выпадающем меню — каждой части UI, которую вы видите в интернете. -React позволяет вам объединять разметку, CSS и JavaScript в пользовательские "компоненты", **переиспользуемые элементы UI для вашего приложения**. Код оглавления, который вы видели выше, можно превратить в компонент ``, который можно отрендерить на каждой странице. Внутри он всё ещё использует те же HTML-теги, такие как `
            `, `

            ` и т.д. +С React можно объединять разметку, CSS и JavaScript в ваши собственные "компоненты", **переиспользуемые элементы UI для вашего приложения**. Код оглавления выше, можно превратить в компонент `` и отрендерить его на любой странице. Внутри он всё ещё использует те же HTML-теги, такие как `
            `, `

            ` и т.д. -Как и с HTML-тегами, вы можете комбинировать, упорядочивать и вкладывать компоненты для создания целых страниц. Например, страница документации, которую вы сейчас читаете, состоит из React-компонентов: +Как и HTML-теги, компоненты можно комбинировать, упорядочивать и вкладывать друг в друга для создания целых страниц. Например, страница документации, которую вы сейчас читаете, состоит из React-компонентов: ```js @@ -51,7 +51,7 @@ React позволяет вам объединять разметку, CSS и Ja ``` -По мере роста вашего проекта вы заметите, что многие из ваших дизайнов можно создать, переиспользуя уже готовые компоненты, а это ускорит разработку. Наше оглавление выше может быть добавлено на любой экран как ``! Дайте резкий старт своему проекту, используя тысячи компонентов с открытым исходным кодом, которые были созданы React-сообществом, например [Chakra UI](https://chakra-ui.com/) и [Material UI.](https://material-ui.com/) +По мере роста вашего проекта вы заметите, что многие из ваших дизайнов можно создать, переиспользуя уже готовые компоненты, а это ускорит разработку. Наше оглавление выше может быть добавлено на любой экран как ``! Можно дать резкий старт своему проекту, используя тысячи компонентов с открытым исходным кодом, которые были созданы React-сообществом, например [Chakra UI](https://chakra-ui.com/) и [Material UI.](https://material-ui.com/) ## Определение компонента {/*defining-a-component*/} @@ -285,7 +285,7 @@ img { height: 181px; } -Возможно, вы задаётесь вопросом, почему одного только написания `export` недостаточно, чтобы исправить этот пример. Вы можете узнать разницу между `export` и `export default` в разделе [Импорт и Экспорт компонентов.](/learn/importing-and-exporting-components) +Возможно, вы задаётесь вопросом, почему написать лишь `export` недостаточно, чтобы исправить этот пример. Вы можете узнать разницу между `export` и `export default` в разделе [Импорт и Экспорт компонентов.](/learn/importing-and-exporting-components) @@ -358,7 +358,7 @@ img { height: 180px; } #### Найдите ошибку {/*spot-the-mistake*/} -Что-то не так с тем, как объявлен и использован компонента `Profile`. Сможете найти ошибку? (Попробуйте вспомнить, как React отличает компоненты от обычных тегов HTML!) +Что-то не так с тем, как объявлен и использован компонент `Profile`. Сможете найти ошибку? (Попробуйте вспомнить, как React отличает компоненты от обычных тегов HTML!) From 9a9af32a3f6c748bdf00dda2906b07a4930c07c9 Mon Sep 17 00:00:00 2001 From: XamzatJR Date: Mon, 1 May 2023 13:51:44 +0300 Subject: [PATCH 098/233] Update Fragment.md translation --- src/content/reference/react/Fragment.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/content/reference/react/Fragment.md b/src/content/reference/react/Fragment.md index 73bd627b4..6daf46bf6 100644 --- a/src/content/reference/react/Fragment.md +++ b/src/content/reference/react/Fragment.md @@ -4,7 +4,7 @@ title: (<>...) -``, часто используемый с помощью синтаксиса `<>...`, позволяет группировать элементы без оборачивания в дополнительный тег. +``, или `<>...`, позволяет группировать элементы без тега-обертки. ```js <> @@ -23,7 +23,7 @@ title: (<>...) ### `` {/*fragment*/} -Оберните элементы в ``, чтобы сгруппировать их вместе в тех случаях, когда вам необходим единственный элемент. Группировка элементов с помощью `Fragment` не влияет на конечный DOM; он остается таким же, как если бы элементы не были сгруппированы. Пустой JSX-тег `<>` в большинстве случаев является сокращением для ``. +Оберните элементы в ``, чтобы объеденить их, когда вам нужен один элемент. Группировка элементов с помощью `Fragment` не влияет на конечный DOM; он остается таким же, как если бы элементы не были сгруппированы. Пустой JSX-тег `<>` обычно является сокращением для ``. #### Пропсы {/*props*/} @@ -31,7 +31,7 @@ title: (<>...) #### Предостережения {/*caveats*/} -- Если вам необходимо передать `key` фрагменту, вы не можете использовать краткий синтаксис `<>...`. Вы должны явно импортировать `Fragment` из `'react'` и рендерить `...`. +- Если вы хотите передать `key` фрагменту, то воспользоваться краткой формой `<>...` не выйдет. Вы должны явно импортировать `Fragment` из `'react'` и рендерить `...`. - React не [сбрасывает состояние](/learn/preserving-and-resetting-state) когда вы переключаетесь между рендерингом `<>` к `[]` или обратно, или между `<>` и ``. Однако, это работает только на одном уровне вложенности. Например, когда вы переключаетесь от `<><>` к ``, то состояние будет сброшено. Точную семантику можно посмотреть [здесь.](https://gist.github.com/clemmy/b3ef00f9507909429d8aa0d3ee4f986b) @@ -41,7 +41,7 @@ title: (<>...) ### Возвращение нескольких элементов {/*returning-multiple-elements*/} -Используйте `Fragment` или аналогичный синтаксис `<>...`, чтобы сгруппировать несколько элементов. Вы можете использовать его для размещения нескольких элементов в любом месте, где может находиться один элемент. Например, компонент может возвращать только один элемент, но используя `Fragment`, вы можете сгруппировать несколько элементов вместе и затем вернуть их как группу: +Используйте `Fragment` или `<>...`, чтобы сгруппировать несколько элементов. Вы можете применить его для размещения нескольких элементов в любом месте, где может находиться один элемент. Например, компонент может возвращать только один элемент, но используя `Fragment`, можно объеденить несколько элементов, а затем вернуть их: ```js {3,6} function Post() { @@ -54,7 +54,7 @@ function Post() { } ``` -Фрагменты полезны тем, что группировка элементов с их помощью не влияет на отображение элементов на странице или стили, в отличие от случая, когда вы оборачиваете элементы в другой контейнер, например, в DOM-элемент. Если вы проверите этот пример с помощью инструментов браузера, то увидите, что все DOM-узлы `

            ` и `

            ` отображаются как соседи без оберток вокруг них: +Фрагменты полезны тем, что группировка элементов с их помощью не влияет на отображение элементов на странице или стили, в отличие от случая, когда вы используете в роли контейнера DOM-элемент. Изучив этот пример в браузере с помощью инструментов разработчика, вы увидите, что все DOM-узлы `

            ` и `

            ` отображаются рядом и без оберток: @@ -160,7 +160,7 @@ function DateRangePicker({ start, end }) { ### Рендеринг списка фрагментов {/*rendering-a-list-of-fragments*/} -Рассмотрим ситуацию, когда вам нужно явно написать `Fragment`, вместо использования синтаксиса `<>`. Это может понадобиться, когда вы [рендерите несколько элементов в цикле](/learn/rendering-lists) и каждому элементу нужно присвоить `key`. Если элементы в цикле являются фрагментами, то вам необходимо использовать стандартный синтаксис JSX-элементов, чтобы предоставить атрибут `key`: +Рассмотрим ситуацию, где вы должны использовать `Fragment`, а не его краткую форму `<>`. Когда вы [рендерите несколько элементов в цикле](/learn/rendering-lists), то каждому из них нужно присвоить `key`. Если элементы цикла являются фрагментами, то вам необходимо использовать стандартный синтаксис JSX-элементов, чтобы это сделать: ```js {3,6} function Blog() { @@ -173,7 +173,7 @@ function Blog() { } ``` -Вы можете проверить DOM, чтобы убедиться, что вокруг дочерних элементов фрагмента нет оберток: +Вы можете проверить DOM и убедиться, что дочерние элементы фрагмента ни во что не обернуты: From f8806c77231dbd4d95321c40d183ee808d2e58f2 Mon Sep 17 00:00:00 2001 From: Viacheslav Makarov <9768704+mekarthedev@users.noreply.github.com> Date: Mon, 1 May 2023 14:09:53 +0200 Subject: [PATCH 099/233] Translated more usage of useDeferredValue --- .../reference/react/useDeferredValue.md | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/content/reference/react/useDeferredValue.md b/src/content/reference/react/useDeferredValue.md index 44c290e54..42296e949 100644 --- a/src/content/reference/react/useDeferredValue.md +++ b/src/content/reference/react/useDeferredValue.md @@ -730,11 +730,11 @@ input { margin: 10px; } --- -### Deferring re-rendering for a part of the UI {/*deferring-re-rendering-for-a-part-of-the-ui*/} +### Откладывание повторного рендеринга для части UI {/*deferring-re-rendering-for-a-part-of-the-ui*/} -You can also apply `useDeferredValue` as a performance optimization. It is useful when a part of your UI is slow to re-render, there's no easy way to optimize it, and you want to prevent it from blocking the rest of the UI. +`useDeferredValue` -- это в том числе инструмент оптимизации. Его можно применить в ситуации, когда какая-то часть вашего UI требует вычислительно долгого рендеринга, с которым очень трудно что-то сделать, но при этом вы не хотите из-за этого постоянно блокировать рендеринг остального UI. -Imagine you have a text field and a component (like a chart or a long list) that re-renders on every keystroke: +Представьте, что в вашем приложении некий сложный компонент (график, либо очень длинный список) каждый раз заново рендерится по каждому нажатию клавиши в поле ввода: ```js function App() { @@ -748,7 +748,7 @@ function App() { } ``` -First, optimize `SlowList` to skip re-rendering when its props are the same. To do this, [wrap it in `memo`:](/reference/react/memo#skipping-re-rendering-when-props-are-unchanged) +Для начала, вы можете [обернуть `SlowList` в `memo`](/reference/react/memo#skipping-re-rendering-when-props-are-unchanged), чтобы рендеринг `SlowList` не повторялся, если его пропсы не меняются. ```js {1,3} const SlowList = memo(function SlowList({ text }) { @@ -756,9 +756,9 @@ const SlowList = memo(function SlowList({ text }) { }); ``` -However, this only helps if the `SlowList` props are *the same* as during the previous render. The problem you're facing now is that it's slow when they're *different,* and when you actually need to show different visual output. +Но этого не достаточно. Ведь так рендеринг ускорится, только если всегда передавать в `SlowList` *одни и те же* значения пропсов. Проблема в том, что рендеринг всё ещё медленный, если передавать *другие* значения пропсов, требующие другой визуализации. -Concretely, the main performance problem is that whenever you type into the input, the `SlowList` receives new props, and re-rendering its entire tree makes the typing feel janky. In this case, `useDeferredValue` lets you prioritize updating the input (which must be fast) over updating the result list (which is allowed to be slower): +Конкретно в этом примере, `SlowList` будет на каждый ввод символа получать новые пропсы и своим рендерингом блокировать остальной интерфейс. Из-за чего ввод будет слишком заметно "заедать". В такой ситуации с помощью `useDeferredValue` можно сделать обновления поля ввода всегда более приоритетными (отзывчивее), чем обновления списка (которые в любом случае медленные): ```js {3,7} function App() { @@ -773,13 +773,13 @@ function App() { } ``` -This does not make re-rendering of the `SlowList` faster. However, it tells React that re-rendering the list can be deprioritized so that it doesn't block the keystrokes. The list will "lag behind" the input and then "catch up". Like before, React will attempt to update the list as soon as possible, but will not block the user from typing. +Собственно сам рендеринг `SlowList` не станет от этого быстрее. Однако теперь React понимает, что не нужно блокировать обработку нажатий рендерингом списка. Визуально список будет как бы "отставать" от ввода, а затем его "догонять". Конечно, как и до оптимизации, React будет стараться обновлять список как можно раньше, но уже не в ущерб возможности печатать. - + -#### Deferred re-rendering of the list {/*deferred-re-rendering-of-the-list*/} +#### Отложенный рендеринг списка {/*deferred-re-rendering-of-the-list*/} -In this example, each item in the `SlowList` component is **artificially slowed down** so that you can see how `useDeferredValue` lets you keep the input responsive. Type into the input and notice that typing feels snappy while the list "lags behind" it. +В этом примере каждый элемент в компоненте `SlowList` **искусственно замедлен**, чтобы продемонстрировать, как `useDeferredValue` позволяет сохранить отзывчивость поля ввода. Попробуйте попечатать в поле ввода -- оцените свои ощущения от того, как мгновенно оно реагирует на ввод, хотя список при этом заметно отстаёт. @@ -803,7 +803,7 @@ export default function App() { import { memo } from 'react'; const SlowList = memo(function SlowList({ text }) { - // Log once. The actual slowdown is inside SlowItem. + // Собственно замедление происходит в SlowItem. console.log('[ARTIFICIALLY SLOW] Rendering 250 '); let items = []; @@ -820,12 +820,12 @@ const SlowList = memo(function SlowList({ text }) { function SlowItem({ text }) { let startTime = performance.now(); while (performance.now() - startTime < 1) { - // Do nothing for 1 ms per item to emulate extremely slow code + // Крутимся в цикле одну миллисекунду, эмулируя очень медленный рендеринг } return (

          1. - Text: {text} + Текст: {text}
          2. ) } @@ -853,11 +853,11 @@ export default SlowList; -#### Unoptimized re-rendering of the list {/*unoptimized-re-rendering-of-the-list*/} +#### Неоптимизированный рендеринг списка {/*unoptimized-re-rendering-of-the-list*/} -In this example, each item in the `SlowList` component is **artificially slowed down**, but there is no `useDeferredValue`. +В этом примере каждый элемент в компоненте `SlowList` **искусственно замедлен**, но `useDeferredValue` уже не используется. -Notice how typing into the input feels very janky. This is because without `useDeferredValue`, each keystroke forces the entire list to re-render immediately in a non-interruptible way. +Обратите внимание, как поле ввода заедает при каждом нажатии. Так происходит потому, что без `useDeferredValue` каждое нажатие клавиши требует немедленно заново отрендерить список. Причём без возможности прерывать рендеринг. @@ -880,7 +880,7 @@ export default function App() { import { memo } from 'react'; const SlowList = memo(function SlowList({ text }) { - // Log once. The actual slowdown is inside SlowItem. + // Собственно замедление происходит в SlowItem. console.log('[ARTIFICIALLY SLOW] Rendering 250 '); let items = []; @@ -897,12 +897,12 @@ const SlowList = memo(function SlowList({ text }) { function SlowItem({ text }) { let startTime = performance.now(); while (performance.now() - startTime < 1) { - // Do nothing for 1 ms per item to emulate extremely slow code + // Крутимся в цикле одну миллисекунду, эмулируя очень медленный рендеринг } return (
          3. - Text: {text} + Текст: {text}
          4. ) } @@ -934,7 +934,7 @@ export default SlowList; -This optimization requires `SlowList` to be wrapped in [`memo`.](/reference/react/memo) This is because whenever the `text` changes, React needs to be able to re-render the parent component quickly. During that re-render, `deferredText` still has its previous value, so `SlowList` is able to skip re-rendering (its props have not changed). Without [`memo`,](/reference/react/memo) it would have to re-render anyway, defeating the point of the optimization. +Для такой оптимизации `SlowList` должен обязательно быть обёрнут в [`memo`.](/reference/react/memo) Цель оптимизации ведь в том, чтобы при каждом изменении `text` React рендерил родительский компонент (`App`) как можно быстрей. Во время этого рендеринга в `deferredText` будет такое же значение, как и в прошлый рендеринг -- а значит пропсы `SlowList` не изменились, и нет нужды заново рендерить список. Но без [`memo`](/reference/react/memo) список всё равно будет рендерится ещё раз -- что делает саму оптимизацию бессмысленной. From 1971b3610b412c815ade1464086167ee3a9ed4f0 Mon Sep 17 00:00:00 2001 From: Viacheslav Makarov <9768704+mekarthedev@users.noreply.github.com> Date: Mon, 1 May 2023 18:29:32 +0200 Subject: [PATCH 100/233] Translated last deep dive of useDeferredValue --- src/content/reference/react/useDeferredValue.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/content/reference/react/useDeferredValue.md b/src/content/reference/react/useDeferredValue.md index 42296e949..e3e73bae5 100644 --- a/src/content/reference/react/useDeferredValue.md +++ b/src/content/reference/react/useDeferredValue.md @@ -940,19 +940,19 @@ export default SlowList; -#### How is deferring a value different from debouncing and throttling? {/*how-is-deferring-a-value-different-from-debouncing-and-throttling*/} +#### Чем отложенное обновление отличается от дебаунсинга и тротлинга? {/*how-is-deferring-a-value-different-from-debouncing-and-throttling*/} -There are two common optimization techniques you might have used before in this scenario: +Возможно, вы в похожей ситуации применили бы один из двух распространённых приёмов: -- *Debouncing* means you'd wait for the user to stop typing (e.g. for a second) before updating the list. -- *Throttling* means you'd update the list every once in a while (e.g. at most once a second). +- *Дебаунсинг (debouncing)*, при котором приложение сначала бы дожидалось, когда пользователь перестанет печатать (уже секунду не печатал, например), и потом обновляло список. +- *Тротлинг (throttling)*, при котором, как бы быстро пользователь не печатал, приложение обновляло бы список не чаще одного раза за какой-то период (раз в секунду, например). -While these techniques are helpful in some cases, `useDeferredValue` is better suited to optimizing rendering because it is deeply integrated with React itself and adapts to the user's device. +Это отличные и часто очень полезные техники. Но `useDeferredValue` лучше подходит для оптимизации рендеринга потому, что он, тесно взаимодействуя с React, может подстраиваться под возможности устройства пользователя. -Unlike debouncing or throttling, it doesn't require choosing any fixed delay. If the user's device is fast (e.g. powerful laptop), the deferred re-render would happen almost immediately and wouldn't be noticeable. If the user's device is slow, the list would "lag behind" the input proportionally to how slow the device is. +Можно не привязываться к какой-то фиксированной задержке. У пользователей с быстрым, мощным устройством фоновый рендеринг будет выполняться быстро и без заметной задержки. А у пользователей со слабым устройством список будет "отставать" ровно на столько, на сколько позволяет устройство. -Also, unlike with debouncing or throttling, deferred re-renders done by `useDeferredValue` are interruptible by default. This means that if React is in the middle of re-rendering a large list, but the user makes another keystroke, React will abandon that re-render, handle the keystroke, and then start rendering in background again. By contrast, debouncing and throttling still produce a janky experience because they're *blocking:* they merely postpone the moment when rendering blocks the keystroke. +Кроме того, в отличие от дебаунсинга и тротлинга, отложенный с помощью `useDeferredValue` рендеринг можно прервать. Это значит, что если, например, пользователь введёт очередной символ, пока в фоне рендерится большой сложный список, React прервёт этот рендеринг, обработает ввод, и затем снова запустит рендеринг в фоне. При этом с дебаунсингом или тротлингом в такой же ситуации интерфейс всё ещё будет тормозить и заедать -- ведь эти приёмы не устраняют собственно *блокировку* ввода: с ними она случается просто либо позже, либо реже. -If the work you're optimizing doesn't happen during rendering, debouncing and throttling are still useful. For example, they can let you fire fewer network requests. You can also use these techniques together. +Когда нужно оптимизировать что-то помимо рендеринга, дебаунсинг и тротлинг могут наоборот быть очень полезны. Например, они помогут уменьшить количество запросов в сеть. А ещё их можно совмещать с описанными здесь техниками. From 7f03576b85dea333e50dc4972b4305bffaa02def Mon Sep 17 00:00:00 2001 From: Viacheslav Makarov <9768704+mekarthedev@users.noreply.github.com> Date: Mon, 1 May 2023 19:12:53 +0200 Subject: [PATCH 101/233] Fix some overall wording for useDeferredValue --- src/content/reference/react/useDeferredValue.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/content/reference/react/useDeferredValue.md b/src/content/reference/react/useDeferredValue.md index e3e73bae5..9d0caa2fb 100644 --- a/src/content/reference/react/useDeferredValue.md +++ b/src/content/reference/react/useDeferredValue.md @@ -46,19 +46,19 @@ function SearchPage() { - Значения, которые вы передаёте в `useDeferredValue`, должны либо быть примитивного типа (как, например, строки или числа), либо должны создаваться **не** во время рендеринга. Если вы будете во время рендеринга каждый раз передавать в `useDeferredValue` свеже созданный объект, то так вы будете постоянно запускать ненужный фоновый рендеринг. -- Если `useDeferredValue` получит новое значение (сравнение будет через [`Object.is`](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Object/is)), то помимо текущего рендеринга (в котором хук вернёт старое значение), дополнительно в фоне запустится рендеринг для собственно нового значения. Но этот фоновый рендеринг может прерваться: если значение параметра `value` изменится ещё раз, то React перезапустит фоновый рендеринг заново. Например, если пользователь будет печатать быстрее, чем зависящий от ввода график будет успевать в фоне рендерить предыдущий ввод, то на экране график обновится, только когда пользователь перестанет печатать. +- Когда `useDeferredValue` получит другое значение (сравниваться будет через [`Object.is`](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Object/is)), помимо текущего рендеринга (в котором хук вернёт старое значение), дополнительно в фоне запустится рендеринг для собственно нового значения. Но этот фоновый рендеринг может прерваться: если значение параметра `value` изменится ещё раз, то React перезапустит фоновый рендеринг заново. Например, если пользователь будет печатать быстрее, чем зависящий от ввода график будет успевать в фоне рендерить предыдущий ввод -- график в таком случае обновится, только когда пользователь перестанет печатать. -- `useDeferredValue` интегрирован с [``.](/reference/react/Suspense) Если фоновое обновление для нового значения задержится, то вместо заглушки пользователь просто увидит старое значение, пока загружаются данные для фонового обновления. +- `useDeferredValue` интегрирован с [``.](/reference/react/Suspense) Если фоновое обновление для нового значения задержится, то вместо заглушки `` пользователь просто увидит старое значение, пока загружаются данные для фонового обновления. - Сам по себе `useDeferredValue` не защищает от лишних запросов в сеть. -- `useDeferredValue` не пытается отложить обновление на какое-то конкретное количество времени. Как только React закончит с текущим рендерингом, он сразу же запустит в фоне рендеринг нового отложенного значения. А любые обновления из-за внешних событий (пользователь печатает, например), будут просто более приоритетными, чем фоновый рендеринг, и прервут его. +- `useDeferredValue` не пытается отложить обновление на какое-то конкретное количество времени. Как только React закончит с текущим рендерингом, он сразу же запустит в фоне рендеринг для новой версии отложенного значения. А любые обновления из-за внешних событий (пользователь печатает, например), будут просто более приоритетными, чем фоновый рендеринг, и прервут его. - Эффекты фонового рендеринга, вызванного `useDeferredValue`, сработают, только когда React зафиксирует результат на экране. Если фоновый рендеринг запросит задержку, то эффекты сработают только после того, как данные загрузятся, а экран обновится. --- -## Использование {/*usage*/} +## Применение {/*usage*/} ### Отображение старых данных, пока загружаются новые {/*showing-stale-content-while-fresh-content-is-loading*/} @@ -284,7 +284,7 @@ input { margin: 10px; }
            -Однако здесь можно применить другой частый паттерн в UI: *отложить* обновление списка результатов, продолжив показывать старые результаты, пока не подготовятся новые. Чтобы передавать в результаты поиска отложенную версию запроса, можно применить `useDeferredValue`: +Однако здесь можно применить другой частый паттерн в UI: *отложить* обновление списка результатов, продолжив показывать старые результаты, пока не подготовятся новые. Чтобы показать результаты поиска по отложенной версии запроса, можно применить `useDeferredValue`: ```js {3,11} export default function App() { From 13e3dbe65bfd9acd2439106f9d4118ff4bf0ee06 Mon Sep 17 00:00:00 2001 From: Viacheslav Makarov <9768704+mekarthedev@users.noreply.github.com> Date: Mon, 1 May 2023 19:19:27 +0200 Subject: [PATCH 102/233] Better translation for 'usage' --- src/content/reference/react/useId.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/reference/react/useId.md b/src/content/reference/react/useId.md index 1444c1d9c..481d492ba 100644 --- a/src/content/reference/react/useId.md +++ b/src/content/reference/react/useId.md @@ -48,7 +48,7 @@ function PasswordField() { --- -## Использование {/*usage*/} +## Применение {/*usage*/} From 27433f734fdcaab9a2834942b744411a2b8060ee Mon Sep 17 00:00:00 2001 From: Maxim Tereshko Date: Tue, 2 May 2023 10:14:03 +0200 Subject: [PATCH 103/233] Update src/content/learn/react-developer-tools.md Co-authored-by: Khamzat <67521340+XamzatJR@users.noreply.github.com> --- src/content/learn/react-developer-tools.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/react-developer-tools.md b/src/content/learn/react-developer-tools.md index f13c90567..c554df9c6 100644 --- a/src/content/learn/react-developer-tools.md +++ b/src/content/learn/react-developer-tools.md @@ -54,7 +54,7 @@ react-devtools ![React Developer Tools standalone](/images/docs/react-devtools-standalone.png) ## Мобильные устройства (React Native) {/*mobile-react-native*/} -React Developer Tools также может использоваться для отладки приложений, созданных с помощью [React Native](https://reactnative.dev/). +React Developer Tools также можно использовать для отладки приложений, созданных с помощью [React Native](https://reactnative.dev/). Самый простой способ использования React Developer Tools - установить их глобально: ```bash From 1ea464bb1cb930f944015c6242b4aef47903fa2c Mon Sep 17 00:00:00 2001 From: ianreas Date: Tue, 2 May 2023 05:08:26 -0400 Subject: [PATCH 104/233] Translate startTransition --- .../reference/react/startTransition.md | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/content/reference/react/startTransition.md b/src/content/reference/react/startTransition.md index 4773d77c7..50eb693e1 100644 --- a/src/content/reference/react/startTransition.md +++ b/src/content/reference/react/startTransition.md @@ -1,10 +1,10 @@ --- -title: startTransition +Заголовок: startTransition --- -`startTransition` lets you update the state without blocking the UI. +`startTransition` позволяет обновлять состояние без блокировки интерфейса. ```js startTransition(scope) @@ -16,11 +16,11 @@ startTransition(scope) --- -## Reference {/*reference*/} +## Справочник {/*reference*/} ### `startTransition(scope)` {/*starttransitionscope*/} -The `startTransition` function lets you mark a state update as a transition. +Функция `startTransition` позволяет пометить обновление состояния как переход. ```js {7,9} import { startTransition } from 'react'; @@ -37,37 +37,37 @@ function TabContainer() { } ``` -[See more examples below.](#usage) +[См. другие примеры ниже.](#usage) -#### Parameters {/*parameters*/} +#### Параметры {/*parameters*/} -* `scope`: A function that updates some state by calling one or more [`set` functions.](/reference/react/useState#setstate) React immediately calls `scope` with no parameters and marks all state updates scheduled synchronously during the `scope` function call as transitions. They will be [non-blocking](/reference/react/useTransition#marking-a-state-update-as-a-non-blocking-transition) and [will not display unwanted loading indicators.](/reference/react/useTransition#preventing-unwanted-loading-indicators) +* `scope`: Функция, которая обновляет состояние, вызывая одну или несколько [функций `set`.](/reference/react/useState#setstate) React немедленно вызывает `scope` без параметров и помечает все обновления состояния, запланированные синхронно во время вызова функции scope, как переходы. Они будут [неблокирующими](/reference/react/useTransition#marking-a-state-update-as-a-non-blocking-transition) и [не будут отображать нежелательные индикаторы загрузки.](/reference/react/useTransition#preventing-unwanted-loading-indicators) -#### Returns {/*returns*/} +#### Возвращаемое значение {/*returns*/} -`startTransition` does not return anything. +`startTransition` ничего не возвращает. -#### Caveats {/*caveats*/} +#### Замечания {/*caveats*/} -* `startTransition` does not provide a way to track whether a transition is pending. To show a pending indicator while the transition is ongoing, you need [`useTransition`](/reference/react/useTransition) instead. +* `startTransition` не предоставляет способа отслеживать, ожидает ли переход выполнения. Чтобы показать индикатор ожидания во время выполнения перехода, необходимо использовать [`useTransition`](/reference/react/useTransition). -* You can wrap an update into a transition only if you have access to the `set` function of that state. If you want to start a transition in response to some prop or a custom Hook return value, try [`useDeferredValue`](/reference/react/useDeferredValue) instead. +* Вы можете обернуть обновление в переход только в том случае, если у вас есть доступ к функции `set` для этого состояния. Если вы хотите начать переход в ответ на какой-то проп или значение, возвращаемое пользовательским хуком, попробуйте использовать [`useDeferredValue`](/reference/react/useDeferredValue). -* The function you pass to `startTransition` must be synchronous. React immediately executes this function, marking all state updates that happen while it executes as transitions. If you try to perform more state updates later (for example, in a timeout), they won't be marked as transitions. +* Функция, передаваемая в `startTransition`, должна быть синхронной. React немедленно выполняет эту функцию, помечая как переходы все обновления состояния которые происходят во время ее выполнения. Если вы попытаетесь выполнить дополнительные обновления состояния позже (например, в таймауте), они не будут помечены как переходы. -* A state update marked as a transition will be interrupted by other state updates. For example, if you update a chart component inside a transition, but then start typing into an input while the chart is in the middle of a re-render, React will restart the rendering work on the chart component after handling the input state update. +* Обновление состояния, помеченное как переход, будет прервано другими обновлениями состояния. Например, если вы обновите компонент диаграммы внутри перехода, но затем начнете вводить текст в поле ввода, пока диаграмма находится в процессе повторного рендеринга, React перезапустит процесс рендеринга компонента диаграммы после обработки обновления состояния в поле ввода. -* Transition updates can't be used to control text inputs. +* Обновления перехода не могут использоваться для управления текстовыми полями ввода. -* If there are multiple ongoing transitions, React currently batches them together. This is a limitation that will likely be removed in a future release. +* В случае наличия нескольких одновременных переходов, React в настоящее время группирует их вместе. Это ограничение, вероятно, будет устранено в будущих релизах. --- -## Usage {/*usage*/} +## Применение {/*usage*/} -### Marking a state update as a non-blocking transition {/*marking-a-state-update-as-a-non-blocking-transition*/} +### Пометка обновления состояния как неблокирующего перехода. {/*marking-a-state-update-as-a-non-blocking-transition*/} -You can mark a state update as a *transition* by wrapping it in a `startTransition` call: +Вы можете пометить обновление состояния как *переход*, обернув его в вызов `startTransition`: ```js {7,9} import { startTransition } from 'react'; @@ -84,14 +84,14 @@ function TabContainer() { } ``` -Transitions let you keep the user interface updates responsive even on slow devices. +Переходы позволяют сохранить отзывчивость обновлений интерфейса даже на медленных устройствах. -With a transition, your UI stays responsive in the middle of a re-render. For example, if the user clicks a tab but then change their mind and click another tab, they can do that without waiting for the first re-render to finish. +С помощью перехода ваш UI остается отзывчивым даже во время повторного рендера. Например, если пользователь нажимает на вкладку, но затем меняет свое решение и нажимает на другую вкладку, он может это сделать, не дожидаясь завершения первого перерендеринга. -`startTransition` is very similar to [`useTransition`](/reference/react/useTransition), except that it does not provide the `isPending` flag to track whether a transition is ongoing. You can call `startTransition` when `useTransition` is not available. For example, `startTransition` works outside components, such as from a data library. +`startTransition` очень похож на [`useTransition`](/reference/react/useTransition), за исключением того, что он не предоставляет флаг `isPending` для отслеживания того, идет ли в данный момент переход. Вы можете вызвать `startTransition`, когда `useTransition` недоступен. Например, `startTransition` работает вне компонентов из например, библиотеки данных. -[Learn about transitions and see examples on the `useTransition` page.](/reference/react/useTransition) +[Узнайте о переходах и посмотрите примеры на странице `useTransition`.](/reference/react/useTransition) - + \ No newline at end of file From 25f4522d94849b644bb94f2f0e14396be53fef03 Mon Sep 17 00:00:00 2001 From: Fedya Petrakov Date: Tue, 2 May 2023 17:12:55 +0300 Subject: [PATCH 105/233] Update src/content/reference/react/components.md Co-authored-by: Nick Tishkevich --- src/content/reference/react/components.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/reference/react/components.md b/src/content/reference/react/components.md index 8e67e1e27..6b5104436 100644 --- a/src/content/reference/react/components.md +++ b/src/content/reference/react/components.md @@ -13,7 +13,7 @@ title: "Встроенные react-компоненты" ## Встроенные компоненты {/*built-in-components*/} * [``](/reference/react/Fragment), или `<>...`, объединяет несколько JSX узлов. -* [``](/reference/react/Profiler) измеряет производительность рендера компонентов. +* [``](/reference/react/Profiler) позволяет вам измерять производительность рендеринга React-дерева программно. * [``](/reference/react/Suspense) отображает заглушку, пока загружаются дочерние компоненты. * [``](/reference/react/StrictMode) включает дополнительные проверки в режиме разработки, они помогают находить баги раньше. From fdb21f4f5e01290a6e6729f60714ec90f3f9e955 Mon Sep 17 00:00:00 2001 From: Fedya Petrakov Date: Tue, 2 May 2023 17:14:33 +0300 Subject: [PATCH 106/233] Update src/content/reference/react/components.md Co-authored-by: Nick Tishkevich --- src/content/reference/react/components.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/reference/react/components.md b/src/content/reference/react/components.md index 6b5104436..987e5f069 100644 --- a/src/content/reference/react/components.md +++ b/src/content/reference/react/components.md @@ -1,5 +1,5 @@ --- -title: "Встроенные react-компоненты" +title: "Встроенные React-компоненты" --- From d9904e5a8f2d43c8251ffa291df2dd29967bbd97 Mon Sep 17 00:00:00 2001 From: Fedya Petrakov Date: Tue, 2 May 2023 17:15:08 +0300 Subject: [PATCH 107/233] Update components.md --- src/content/reference/react/components.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/reference/react/components.md b/src/content/reference/react/components.md index 987e5f069..a0f238d0b 100644 --- a/src/content/reference/react/components.md +++ b/src/content/reference/react/components.md @@ -4,7 +4,7 @@ title: "Встроенные React-компоненты" -Реакт из коробки предоставляет несколько компонентов. +React из коробки предоставляет несколько компонентов. From 219a3e2d2b7bc1dda1ef87787f7fd70f0e8840ff Mon Sep 17 00:00:00 2001 From: Fedya Petrakov Date: Tue, 2 May 2023 17:16:40 +0300 Subject: [PATCH 108/233] Update sidebarReference.json --- src/sidebarReference.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sidebarReference.json b/src/sidebarReference.json index 6ac7b51ee..f009cca0e 100644 --- a/src/sidebarReference.json +++ b/src/sidebarReference.json @@ -73,7 +73,7 @@ ] }, { - "title": "Компоненты", + "title": "Components", "path": "/reference/react/components", "routes": [ { From 84671a27dfafaa24d1436aed0adca82d31151b8b Mon Sep 17 00:00:00 2001 From: Maxim Titov Date: Wed, 3 May 2023 00:00:56 +0600 Subject: [PATCH 109/233] update intro of start a new project page --- src/content/learn/start-a-new-react-project.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/start-a-new-react-project.md b/src/content/learn/start-a-new-react-project.md index c59118f77..8270183cf 100644 --- a/src/content/learn/start-a-new-react-project.md +++ b/src/content/learn/start-a-new-react-project.md @@ -4,7 +4,7 @@ title: Начать новый React-проект -Если вы хотите создать новое приложение или веб-сайт с React, мы советуем начать с одного из уже зарекомендовавших себя фреймворков. Фреймворки дают возможности, которые нужны большинству сайтов, включая маршрутизацию, загрузку данных и генерацию HTML. +Если вы хотите создать новое приложение или веб-сайт с помощью React, мы рекомендуем выбрать один из популярных в сообществе фреймворков на базе React. Фреймворки дают возможности, которые нужны большинству приложений, включая маршрутизацию, загрузку данных и генерацию HTML. From ea12a52f8eb0ed8321378ab5ab6fc19b34fbf386 Mon Sep 17 00:00:00 2001 From: GoncharovaAnna <38956075+GoncharovaAnna@users.noreply.github.com> Date: Wed, 3 May 2023 18:51:56 +0300 Subject: [PATCH 110/233] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B2=D1=8B=D0=B5=20?= =?UTF-8?q?=D0=BF=D1=80=D0=B0=D0=B2=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../react-dom/server/renderToNodeStream.md | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/content/reference/react-dom/server/renderToNodeStream.md b/src/content/reference/react-dom/server/renderToNodeStream.md index a4ab2e570..4bfc8616e 100644 --- a/src/content/reference/react-dom/server/renderToNodeStream.md +++ b/src/content/reference/react-dom/server/renderToNodeStream.md @@ -4,13 +4,13 @@ title: renderToNodeStream -This API will be removed in a future major version of React. Use [`renderToPipeableStream`](/reference/react-dom/server/renderToPipeableStream) instead. +Этот API будет удален в будущей основной версии React. Лучше использовать вместо него [`renderToPipeableStream`](/reference/react-dom/server/renderToPipeableStream). -`renderToNodeStream` renders a React tree to a [Node.js Readable Stream.](https://nodejs.org/api/stream.html#readable-streams) +`renderToNodeStream` отображает дерево React в [Node.js Readable Stream.](https://nodejs.org/api/stream.html#readable-streams) ```js const stream = renderToNodeStream(reactNode) @@ -22,11 +22,11 @@ const stream = renderToNodeStream(reactNode) --- -## Reference {/*reference*/} +## Справка {/*reference*/} ### `renderToNodeStream(reactNode)` {/*rendertonodestream*/} -On the server, call `renderToNodeStream` to get a [Node.js Readable Stream](https://nodejs.org/api/stream.html#readable-streams) which you can pipe into the response. +На сервере вызовите `renderToNodeStream`, чтобы получить [Node.js Readable Stream](https://nodejs.org/api/stream.html#readable-streams), который вы можете передать в ответ. ```js import { renderToNodeStream } from 'react-dom/server'; @@ -35,42 +35,42 @@ const stream = renderToNodeStream(); stream.pipe(response); ``` -On the client, call [`hydrateRoot`](/reference/react-dom/client/hydrateRoot) to make the server-generated HTML interactive. +На клиенте вызовите [`hydrateRoot`](/reference/react-dom/client/hydrateRoot), чтобы сделать интерактивный HTML-код, созданный сервером. -[See more examples below.](#usage) +[Больше примеров ниже.](#usage) -#### Parameters {/*parameters*/} +#### Параметры {/*parameters*/} -* `reactNode`: A React node you want to render to HTML. For example, a JSX element like ``. +* `reactNode`: Узел React, который вы хотите отобразить в HTML. Например, такой JSX элемент как ``. -#### Returns {/*returns*/} +#### Возвращает {/*returns*/} -A [Node.js Readable Stream](https://nodejs.org/api/stream.html#readable-streams) that outputs an HTML string. +[Node.js Readable Stream](https://nodejs.org/api/stream.html#readable-streams), который выводит строку HTML. -#### Caveats {/*caveats*/} +#### Предупреждения {/*caveats*/} -* This method will wait for all [Suspense boundaries](/reference/react/Suspense) to complete before returning any output. +* Этот метод будет ждать всех [Suspense boundaries](/reference/react/Suspense), прежде чем возвращать какие-либо данные. -* As of React 18, this method buffers all of its output, so it doesn't actually provide any streaming benefits. This is why it's recommended that you migrate to [`renderToPipeableStream`](/reference/react-dom/server/renderToPipeableStream) instead. +* Начиная с React 18, этот метод буферизует все выходные данные, поэтому на самом деле он не дает никаких преимуществ потоковой передачи. Поэтому вместо этого рекомендуется перейти на [`renderToPipeableStream`](/reference/react-dom/server/renderToPipeableStream) -* The returned stream is a byte stream encoded in utf-8. If you need a stream in another encoding, take a look at a project like [iconv-lite](https://www.npmjs.com/package/iconv-lite), which provides transform streams for transcoding text. +* Возвращаемый поток представляет собой поток байтов, закодированный в utf-8. Если вам нужен поток в другой кодировке, взгляните на проект [iconv-lite](https://www.npmjs.com/package/iconv-lite), который предоставляет потоки преобразования для перекодирования текста. --- -## Usage {/*usage*/} +## Применение {/*usage*/} -### Rendering a React tree as HTML to a Node.js Readable Stream {/*rendering-a-react-tree-as-html-to-a-nodejs-readable-stream*/} +### Рендеринг дерева React как HTML в Node.js Readable Stream {/*rendering-a-react-tree-as-html-to-a-nodejs-readable-stream*/} -Call `renderToNodeStream` to get a [Node.js Readable Stream](https://nodejs.org/api/stream.html#readable-streams) which you can pipe to your server response: +Вызовите `renderToNodeStream`, чтобы получить [Node.js Readable Stream](https://nodejs.org/api/stream.html#readable-streams), который вы можете передать вашему серверу: ```js {5-6} import { renderToNodeStream } from 'react-dom/server'; -// The route handler syntax depends on your backend framework +// Синтаксис обработчика маршрута зависит от вашей внутренней структуры app.use('/', (request, response) => { const stream = renderToNodeStream(); stream.pipe(response); }); ``` -The stream will produce the initial non-interactive HTML output of your React components. On the client, you will need to call [`hydrateRoot`](/reference/react-dom/client/hydrateRoot) to *hydrate* that server-generated HTML and make it interactive. +Поток произведёт начальный неинтерактивный HTML—вывод ваших компонентов React. На клиенте вам нужно будет вызвать [`hydrateRoot`](/reference/react-dom/client/hydrateRoot), чтобы *hydrate* гидратировать этот сгенерированный сервером HTML и сделать его интерактивным. From 12d19a3503754f046809da0bf62ad591c9edfc61 Mon Sep 17 00:00:00 2001 From: GoncharovaAnna <38956075+GoncharovaAnna@users.noreply.github.com> Date: Wed, 3 May 2023 19:25:51 +0300 Subject: [PATCH 111/233] =?UTF-8?q?=D0=97=D0=B0=D0=BC=D0=B5=D0=BD=D0=B0=20?= =?UTF-8?q?=D1=81=D1=81=D1=8B=D0=BB=D0=BE=D0=BA=20=D0=BD=D0=B0=20=D1=80?= =?UTF-8?q?=D1=83=D1=81=D1=81=D0=BA=D0=B8=D0=B9=20=D0=B0=D0=BD=D0=B0=D0=BB?= =?UTF-8?q?=D0=BE=D0=B3=20=D1=81=D0=B0=D0=B9=D1=82=D0=B0=20Node.js?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../react-dom/server/renderToNodeStream.md | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/content/reference/react-dom/server/renderToNodeStream.md b/src/content/reference/react-dom/server/renderToNodeStream.md index 4bfc8616e..fff43a609 100644 --- a/src/content/reference/react-dom/server/renderToNodeStream.md +++ b/src/content/reference/react-dom/server/renderToNodeStream.md @@ -1,16 +1,16 @@ --- -title: renderToNodeStream +Заголовок: renderToNodeStream --- -Этот API будет удален в будущей основной версии React. Лучше использовать вместо него [`renderToPipeableStream`](/reference/react-dom/server/renderToPipeableStream). +Этот API будет удалён в будущей основной версии React. Лучше использовать вместо него [`renderToPipeableStream`](/reference/react-dom/server/renderToPipeableStream). -`renderToNodeStream` отображает дерево React в [Node.js Readable Stream.](https://nodejs.org/api/stream.html#readable-streams) +`renderToNodeStream` отображает дерево React в [Node.js Readable Stream.](https://nodejsdev.ru/api/stream/#streamreadable) ```js const stream = renderToNodeStream(reactNode) @@ -26,7 +26,7 @@ const stream = renderToNodeStream(reactNode) ### `renderToNodeStream(reactNode)` {/*rendertonodestream*/} -На сервере вызовите `renderToNodeStream`, чтобы получить [Node.js Readable Stream](https://nodejs.org/api/stream.html#readable-streams), который вы можете передать в ответ. +На сервере вызовите `renderToNodeStream`, чтобы получить [Node.js Readable Stream](https://nodejsdev.ru/api/stream/#streamreadable), который вы можете передать в ответ. ```js import { renderToNodeStream } from 'react-dom/server'; @@ -35,9 +35,9 @@ const stream = renderToNodeStream(); stream.pipe(response); ``` -На клиенте вызовите [`hydrateRoot`](/reference/react-dom/client/hydrateRoot), чтобы сделать интерактивный HTML-код, созданный сервером. +На клиенте вызовите [`hydrateRoot`](/reference/react-dom/client/hydrateRoot), чтобы сделать интерактивный HTML—код, созданный сервером. -[Больше примеров ниже.](#usage) +[Смотрите ещё примеры ниже.](#usage) #### Параметры {/*parameters*/} @@ -45,13 +45,13 @@ stream.pipe(response); #### Возвращает {/*returns*/} -[Node.js Readable Stream](https://nodejs.org/api/stream.html#readable-streams), который выводит строку HTML. +[Node.js Readable Stream](https://nodejsdev.ru/api/stream/#streamreadable), который выводит строку HTML. #### Предупреждения {/*caveats*/} -* Этот метод будет ждать всех [Suspense boundaries](/reference/react/Suspense), прежде чем возвращать какие-либо данные. +* Этот метод будет ждать все [Границы задержки](/reference/react/Suspense), прежде чем возвращать какие-либо данные. -* Начиная с React 18, этот метод буферизует все выходные данные, поэтому на самом деле он не дает никаких преимуществ потоковой передачи. Поэтому вместо этого рекомендуется перейти на [`renderToPipeableStream`](/reference/react-dom/server/renderToPipeableStream) +* Начиная с React 18, этот метод буферизует все данные на выходе, из-за чего на самом деле он не даёт никаких преимуществ потоковой передачи. Поэтому вместо этого рекомендуется перейти на [`renderToPipeableStream`](/reference/react-dom/server/renderToPipeableStream) * Возвращаемый поток представляет собой поток байтов, закодированный в utf-8. Если вам нужен поток в другой кодировке, взгляните на проект [iconv-lite](https://www.npmjs.com/package/iconv-lite), который предоставляет потоки преобразования для перекодирования текста. @@ -61,7 +61,7 @@ stream.pipe(response); ### Рендеринг дерева React как HTML в Node.js Readable Stream {/*rendering-a-react-tree-as-html-to-a-nodejs-readable-stream*/} -Вызовите `renderToNodeStream`, чтобы получить [Node.js Readable Stream](https://nodejs.org/api/stream.html#readable-streams), который вы можете передать вашему серверу: +Вызовите `renderToNodeStream`, чтобы получить [Node.js Readable Stream](https://nodejsdev.ru/api/stream/#streamreadable), который вы можете передать вашему серверу: ```js {5-6} import { renderToNodeStream } from 'react-dom/server'; @@ -73,4 +73,4 @@ app.use('/', (request, response) => { }); ``` -Поток произведёт начальный неинтерактивный HTML—вывод ваших компонентов React. На клиенте вам нужно будет вызвать [`hydrateRoot`](/reference/react-dom/client/hydrateRoot), чтобы *hydrate* гидратировать этот сгенерированный сервером HTML и сделать его интерактивным. +Поток произведёт начальный неинтерактивный HTML—вывод ваших компонентов React. На клиенте вам нужно будет вызвать [`hydrateRoot`](/reference/react-dom/client/hydrateRoot), чтобы *гидратировать* этот сгенерированный сервером HTML и сделать его интерактивным. From 7d2f04373b8105ec01a8438feefd4a6a58ebdb8f Mon Sep 17 00:00:00 2001 From: GoncharovaAnna <38956075+GoncharovaAnna@users.noreply.github.com> Date: Wed, 3 May 2023 19:43:11 +0300 Subject: [PATCH 112/233] =?UTF-8?q?=D0=9F=D1=80=D0=B0=D0=B2=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/content/reference/react-dom/server/renderToNodeStream.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/content/reference/react-dom/server/renderToNodeStream.md b/src/content/reference/react-dom/server/renderToNodeStream.md index fff43a609..11d20440f 100644 --- a/src/content/reference/react-dom/server/renderToNodeStream.md +++ b/src/content/reference/react-dom/server/renderToNodeStream.md @@ -49,11 +49,11 @@ stream.pipe(response); #### Предупреждения {/*caveats*/} -* Этот метод будет ждать все [Границы задержки](/reference/react/Suspense), прежде чем возвращать какие-либо данные. +* Этот метод будет ждать [Suspense boundaries](/reference/react/Suspense), прежде чем возвращать какие-либо данные. * Начиная с React 18, этот метод буферизует все данные на выходе, из-за чего на самом деле он не даёт никаких преимуществ потоковой передачи. Поэтому вместо этого рекомендуется перейти на [`renderToPipeableStream`](/reference/react-dom/server/renderToPipeableStream) -* Возвращаемый поток представляет собой поток байтов, закодированный в utf-8. Если вам нужен поток в другой кодировке, взгляните на проект [iconv-lite](https://www.npmjs.com/package/iconv-lite), который предоставляет потоки преобразования для перекодирования текста. +* Возвращаемый поток представляет собой поток байтов, закодированный в utf-8. Если вам нужен поток в другой кодировке, посмотрите проект [iconv-lite](https://www.npmjs.com/package/iconv-lite), который предоставляет потоки преобразования для перекодирования текста. --- From 82f563509edf28897f204eaaecc53d96bff3f187 Mon Sep 17 00:00:00 2001 From: YashinaAnastasia <83582926+YashinaAnastasia@users.noreply.github.com> Date: Wed, 3 May 2023 19:55:07 +0300 Subject: [PATCH 113/233] v1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Первый перевод без правок --- src/content/reference/react/lazy.md | 57 ++++++++++++++--------------- 1 file changed, 28 insertions(+), 29 deletions(-) diff --git a/src/content/reference/react/lazy.md b/src/content/reference/react/lazy.md index ba82d4fe2..0ecaf7d52 100644 --- a/src/content/reference/react/lazy.md +++ b/src/content/reference/react/lazy.md @@ -4,8 +4,7 @@ title: lazy -`lazy` lets you defer loading component's code until it is rendered for the first time. - +`lazy` позволяет отложить загрузку кода компонента до его первого рендеринга. ```js const SomeComponent = lazy(load) ``` @@ -16,11 +15,11 @@ const SomeComponent = lazy(load) --- -## Reference {/*reference*/} +## Справочник {/*reference*/} ### `lazy(load)` {/*lazy*/} -Call `lazy` outside your components to declare a lazy-loaded React component: +Чтобы объявить React компонент ленивой загрузки, вызовите `lazy` вне своих компонентов: ```js import { lazy } from 'react'; @@ -28,41 +27,41 @@ import { lazy } from 'react'; const MarkdownPreview = lazy(() => import('./MarkdownPreview.js')); ``` -[See more examples below.](#usage) +[См. другие примеры ниже.](#usage) -#### Parameters {/*parameters*/} +#### Параметры {/*parameters*/} -* `load`: A function that returns a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) or another *thenable* (a Promise-like object with a `then` method). React will not call `load` until the first time you attempt to render the returned component. After React first calls `load`, it will wait for it to resolve, and then render the resolved value as a React component. Both the returned Promise and the Promise's resolved value will be cached, so React will not call `load` more than once. If the Promise rejects, React will `throw` the rejection reason for the nearest Error Boundary to handle. +* `load`: Функция, которая возвращает [Промис](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Promise) или другой *thenable* (объект, в котором определен метод `then`). Вызова `load` не произойдет до тех пор, пока вы не попытайтесь отрендерить возвращенный компонент. После первого вызова `load`, React будет ждать завершения выполнения команды, а затем отрендерит получившиеся значение как React компонент. Все промисы будут кэшированы, `load` больше вызывать не придется. Если промис отклонили, причина этого будет указана в ближайшем Error Boundary. -#### Returns {/*returns*/} +#### Возвращаемое значение {/*returns*/} -`lazy` returns a React component you can render in your tree. While the code for the lazy component is still loading, attempting to render it will *suspend.* Use [``](/reference/react/Suspense) to display a loading indicator while it's loading. +`lazy` возвращает React компонент, которые можно отрендерить в вашем дереве. Во время загрузки ленивых компонентов попытки их рендора будут *заморожены.* Используйте [``](/reference/react/Suspense) для отображения индикатора во время загрузки. --- -### `load` function {/*load*/} +### Функция `load` {/*load*/} -#### Parameters {/*load-parameters*/} +#### Параметры {/*load-parameters*/} -`load` receives no parameters. +`load` не принимает параметров. -#### Returns {/*load-returns*/} +#### Возвращаемое значение {/*load-returns*/} -You need to return a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) or some other *thenable* (a Promise-like object with a `then` method). It needs to eventually resolve to a valid React component type, such as a function, [`memo`](/reference/react/memo), or a [`forwardRef`](/reference/react/forwardRef) component. +Возвращает [Промис](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Promise) или другой *thenable* (объект, в котором определен метод `then`). В коненом итоге он вернется к действительному React компоненту, например к функции, [`memo`](/reference/react/memo), или [`forwardRef`](/reference/react/forwardRef) компоненту. --- -## Usage {/*usage*/} +## Использование {/*usage*/} -### Lazy-loading components with Suspense {/*suspense-for-code-splitting*/} +### Ленивая загрузка компонентов с Suspense {/*suspense-for-code-splitting*/} -Usually, you import components with the static [`import`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import) declaration: +Обычно импорт компонентов происходит со статическим [`import`](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Statements/import) объявлением: ```js import MarkdownPreview from './MarkdownPreview.js'; ``` -To defer loading this component's code until it's rendered for the first time, replace this import with: +Чтобы отложить загрузку кода этого компонента до его первого рендеринга, замените этот импорт на: ```js import { lazy } from 'react'; @@ -70,9 +69,9 @@ import { lazy } from 'react'; const MarkdownPreview = lazy(() => import('./MarkdownPreview.js')); ``` -This code relies on [dynamic `import()`,](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import) which might require support from your bundler or framework. +Этот код опирается на [динамический `import()`,](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import) который должен поддержиавться вашим бандлером или фреймворком. -Now that your component's code loads on demand, you also need to specify what should be displayed while it is loading. You can do this by wrapping the lazy component or any of its parents into a [``](/reference/react/Suspense) boundary: +Теперь, когда код вашего компонента загружается по запросу, вам также необходимо указать, что должно отображаться во время его загрузки. Это можно сделать путем оборачивания ленивого компонента или его родителя в [``](/reference/react/Suspense) boundary: ```js {1,4} }> @@ -81,7 +80,7 @@ Now that your component's code loads on demand, you also need to specify what sh ``` -In this example, the code for `MarkdownPreview` won't be loaded until you attempt to render it. If `MarkdownPreview` hasn't loaded yet, `Loading` will be shown in its place. Try ticking the checkbox: +Например, код для `MarkdownPreview` не загрузится, пока его не попытаются вызвать. Если `MarkdownPreview` еще не загрузился, на его месте отобразится `Loading`. Попробуйте поставить галочку в чекбоксе: @@ -175,34 +174,34 @@ body { -This demo loads with an artificial delay. The next time you untick and tick the checkbox, `Preview` will be cached, so there will be no loading state. To see the loading state again, click "Reset" on the sandbox. +Это демо загрузится с искуственной задержкой. В следуйщий раз когда вы снимите и поставите галочку, `Preview` будет закэшировано, загрузки не будет. Чтобы снова увидеть загрузку, нужно нажать "Reset" в сэндбоксе. -[Learn more about managing loading states with Suspense.](/reference/react/Suspense) +[Узнать об управлении состояниями загрузки с помощью Suspense.](/reference/react/Suspense) --- -## Troubleshooting {/*troubleshooting*/} +## Траблшутинг {/*troubleshooting*/} -### My `lazy` component's state gets reset unexpectedly {/*my-lazy-components-state-gets-reset-unexpectedly*/} +### Состояние моего `lazy` компонента неожиданно сбрасывается {/*my-lazy-components-state-gets-reset-unexpectedly*/} -Do not declare `lazy` components *inside* other components: +Не объявляйте `lazy` компоненты *внтури* других компонентов: ```js {4-5} import { lazy } from 'react'; function Editor() { - // 🔴 Bad: This will cause all state to be reset on re-renders + // 🔴 Bad: Все состояния сбросятся при ре-рендере const MarkdownPreview = lazy(() => import('./MarkdownPreview.js')); // ... } ``` -Instead, always declare them at the top level of your module: +Вместо этого всегда объявляйте их в верхнем уровне своего модуля: ```js {3-4} import { lazy } from 'react'; -// ✅ Good: Declare lazy components outside of your components +// ✅ Good: lazy компонент объявлен вне ваших компонентов. const MarkdownPreview = lazy(() => import('./MarkdownPreview.js')); function Editor() { From d0af1721db34928e7ca9b7e8034a6a6d72e59cda Mon Sep 17 00:00:00 2001 From: YashinaAnastasia <83582926+YashinaAnastasia@users.noreply.github.com> Date: Wed, 3 May 2023 22:26:42 +0300 Subject: [PATCH 114/233] v1.1 --- src/content/reference/react/lazy.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/reference/react/lazy.md b/src/content/reference/react/lazy.md index 0ecaf7d52..46dd921a8 100644 --- a/src/content/reference/react/lazy.md +++ b/src/content/reference/react/lazy.md @@ -31,7 +31,7 @@ const MarkdownPreview = lazy(() => import('./MarkdownPreview.js')); #### Параметры {/*parameters*/} -* `load`: Функция, которая возвращает [Промис](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Promise) или другой *thenable* (объект, в котором определен метод `then`). Вызова `load` не произойдет до тех пор, пока вы не попытайтесь отрендерить возвращенный компонент. После первого вызова `load`, React будет ждать завершения выполнения команды, а затем отрендерит получившиеся значение как React компонент. Все промисы будут кэшированы, `load` больше вызывать не придется. Если промис отклонили, причина этого будет указана в ближайшем Error Boundary. +* `load`: Функция, которая возвращает [Промис](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Promise) или другой *thenable* (объект, в котором определен метод `then`). Вызова `load` не произойдет до тех пор, пока вы не попытайтесь отрендерить возвращённый компонент. После первого вызова `load`, React будет ждать завершения выполнения команды, а затем отрендерит разрешённое значение как React компонент. Возвращенный промис и разрешенное значение Промиса будут кэшированы, `load` больше вызывать не придется. Если промис отклонили, причина этого будет указана в ближайшем Error Boundary. #### Возвращаемое значение {/*returns*/} From 37a12a658b87a4ed4e2299c8675fcc05c06557fe Mon Sep 17 00:00:00 2001 From: Andrew Clark Date: Wed, 3 May 2023 15:40:44 -0400 Subject: [PATCH 115/233] Next Channel -> Canary Channel (#5992) See https://github.com/facebook/react/pull/26761 for more context. --- src/content/community/versioning-policy.md | 36 +++++++++++----------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/content/community/versioning-policy.md b/src/content/community/versioning-policy.md index b6ffc96de..df3a730c7 100644 --- a/src/content/community/versioning-policy.md +++ b/src/content/community/versioning-policy.md @@ -80,12 +80,12 @@ This section will be most relevant to developers who work on frameworks, librari Each of React's release channels is designed for a distinct use case: - [**Latest**](#latest-channel) is for stable, semver React releases. It's what you get when you install React from npm. This is the channel you're already using today. **Use this for all user-facing React applications.** -- [**Next**](#next-channel) tracks the main branch of the React source code repository. Think of these as release candidates for the next minor semver release. Use this for integration testing between React and third party projects. +- [**Canary**](#canary-channel) tracks the main branch of the React source code repository. Think of these as release candidates for the next minor semver release. Use this for integration testing between React and third party projects. - [**Experimental**](#experimental-channel) includes experimental APIs and features that aren't available in the stable releases. These also track the main branch, but with additional feature flags turned on. Use this to try out upcoming features before they are released. -All releases are published to npm, but only Latest uses semantic versioning. Prereleases (those in the Next and Experimental channels) have versions generated from a hash of their contents and the commit date, e.g. `0.0.0-68053d940-20210623` for Next and `0.0.0-experimental-68053d940-20210623` for Experimental. +All releases are published to npm, but only Latest uses semantic versioning. Prereleases (those in the Canary and Experimental channels) have versions generated from a hash of their contents and the commit date, e.g. `18.3.0-canary-388686f29-20230503` for Canary and `0.0.0-experimental-388686f29-20230503` for Experimental. -**The only officially supported release channel for user-facing applications is Latest**. Next and Experimental releases are provided for testing purposes only, and we provide no guarantees that behavior won't change between releases. They do not follow the semver protocol that we use for releases from Latest. +**The only officially supported release channel for user-facing applications is Latest**. Canary and Experimental releases are provided for testing purposes only, and we provide no guarantees that behavior won't change between releases. They do not follow the semver protocol that we use for releases from Latest. By publishing prereleases to the same registry that we use for stable releases, we are able to take advantage of the many tools that support the npm workflow, like [unpkg](https://unpkg.com) and [CodeSandbox](https://codesandbox.io). @@ -95,49 +95,49 @@ Latest is the channel used for stable React releases. It corresponds to the `lat **If you're not sure which channel you should use, it's Latest.** If you're a React developer, this is what you're already using. You can expect updates to Latest to be extremely stable. Versions follow the semantic versioning scheme, as [described earlier.](#stable-releases) -### Next channel {/*next-channel*/} +### Canary channel {/*canary-channel*/} -The Next channel is a prerelease channel that tracks the main branch of the React repository. We use prereleases in the Next channel as release candidates for the Latest channel. You can think of Next as a superset of Latest that is updated more frequently. +The Canary channel is a prerelease channel that tracks the main branch of the React repository. We use prereleases in the Canary channel as release candidates for the Latest channel. You can think of Canary as a superset of Latest that is updated more frequently. -The degree of change between the most recent Next release and the most recent Latest release is approximately the same as you would find between two minor semver releases. However, **the Next channel does not conform to semantic versioning.** You should expect occasional breaking changes between successive releases in the Next channel. +The degree of change between the most recent Canary release and the most recent Latest release is approximately the same as you would find between two minor semver releases. However, **the Canary channel does not conform to semantic versioning.** You should expect occasional breaking changes between successive releases in the Canary channel. **Do not use prereleases in user-facing applications.** -Releases in Next are published with the `next` tag on npm. Versions are generated from a hash of the build's contents and the commit date, e.g. `0.0.0-68053d940-20210623`. +Releases in Canary are published with the `canary` tag on npm. Versions are generated from a hash of the build's contents and the commit date, e.g. `18.3.0-canary-388686f29-20230503`. -#### Using the next channel for integration testing {/*using-the-next-channel-for-integration-testing*/} +#### Using the canary channel for integration testing {/*using-the-canary-channel-for-integration-testing*/} -The Next channel is designed to support integration testing between React and other projects. +The Canary channel is designed to support integration testing between React and other projects. All changes to React go through extensive internal testing before they are released to the public. However, there are a myriad of environments and configurations used throughout the React ecosystem, and it's not possible for us to test against every single one. If you're the author of a third party React framework, library, developer tool, or similar infrastructure-type project, you can help us keep React stable for your users and the entire React community by periodically running your test suite against the most recent changes. If you're interested, follow these steps: - Set up a cron job using your preferred continuous integration platform. Cron jobs are supported by both [CircleCI](https://circleci.com/docs/2.0/triggers/#scheduled-builds) and [Travis CI](https://docs.travis-ci.com/user/cron-jobs/). -- In the cron job, update your React packages to the most recent React release in the Next channel, using `next` tag on npm. Using the npm cli: +- In the cron job, update your React packages to the most recent React release in the Canary channel, using `canary` tag on npm. Using the npm cli: ```console - npm update react@next react-dom@next + npm update react@canary react-dom@canary ``` Or yarn: ```console - yarn upgrade react@next react-dom@next + yarn upgrade react@canary react-dom@canary ``` - Run your test suite against the updated packages. - If everything passes, great! You can expect that your project will work with the next minor React release. - If something breaks unexpectedly, please let us know by [filing an issue](https://github.com/facebook/react/issues). -A project that uses this workflow is Next.js. (No pun intended! Seriously!) You can refer to their [CircleCI configuration](https://github.com/zeit/next.js/blob/c0a1c0f93966fe33edd93fb53e5fafb0dcd80a9e/.circleci/config.yml) as an example. +A project that uses this workflow is Next.js. You can refer to their [CircleCI configuration](https://github.com/zeit/next.js/blob/c0a1c0f93966fe33edd93fb53e5fafb0dcd80a9e/.circleci/config.yml) as an example. ### Experimental channel {/*experimental-channel*/} -Like Next, the Experimental channel is a prerelease channel that tracks the main branch of the React repository. Unlike Next, Experimental releases include additional features and APIs that are not ready for wider release. +Like Canary, the Experimental channel is a prerelease channel that tracks the main branch of the React repository. Unlike Canary, Experimental releases include additional features and APIs that are not ready for wider release. -Usually, an update to Next is accompanied by a corresponding update to Experimental. They are based on the same source revision, but are built using a different set of feature flags. +Usually, an update to Canary is accompanied by a corresponding update to Experimental. They are based on the same source revision, but are built using a different set of feature flags. -Experimental releases may be significantly different than releases to Next and Latest. **Do not use Experimental releases in user-facing applications.** You should expect frequent breaking changes between releases in the Experimental channel. +Experimental releases may be significantly different than releases to Canary and Latest. **Do not use Experimental releases in user-facing applications.** You should expect frequent breaking changes between releases in the Experimental channel. Releases in Experimental are published with the `experimental` tag on npm. Versions are generated from a hash of the build's contents and the commit date, e.g. `0.0.0-experimental-68053d940-20210623`. @@ -147,11 +147,11 @@ Experimental features are ones that are not ready to be released to the wider pu For example, if the Experimental channel had existed when we announced Hooks, we would have released Hooks to the Experimental channel weeks before they were available in Latest. -You may find it valuable to run integration tests against Experimental. This is up to you. However, be advised that Experimental is even less stable than Next. **We do not guarantee any stability between Experimental releases.** +You may find it valuable to run integration tests against Experimental. This is up to you. However, be advised that Experimental is even less stable than Canary. **We do not guarantee any stability between Experimental releases.** #### How can I learn more about experimental features? {/*how-can-i-learn-more-about-experimental-features*/} -Experimental features may or may not be documented. Usually, experiments aren't documented until they are close to shipping in Next or Latest. +Experimental features may or may not be documented. Usually, experiments aren't documented until they are close to shipping in Canary or Latest. If a feature is not documented, they may be accompanied by an [RFC](https://github.com/reactjs/rfcs). From 883b1351494cdbbf65f0b2aa892c3345de953dd5 Mon Sep 17 00:00:00 2001 From: avarlamova <59831804+avarlamova@users.noreply.github.com> Date: Wed, 3 May 2023 22:53:21 +0300 Subject: [PATCH 116/233] Update importing-and-exporting-components.md --- src/content/learn/importing-and-exporting-components.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/content/learn/importing-and-exporting-components.md b/src/content/learn/importing-and-exporting-components.md index 521e3632a..a4a721d91 100644 --- a/src/content/learn/importing-and-exporting-components.md +++ b/src/content/learn/importing-and-exporting-components.md @@ -4,7 +4,7 @@ title: Импорт и экспорт компонентов -«Магия» компонентов заключается в возможности их повторного использования. Вы можете создавать компоненты, которые состоят из других компонентов. Но по мере увеличения вложенности компонентов зачастую бывает разумным разделить их на отдельные файлы. Это повышает читаемость кода и позволяет повторно использовать компоненты в большем количестве мест. +«Магия» компонентов заключается в возможности их повторного использования: можно создавать компоненты, которые состоят из других компонентов. Но по мере увеличения их вложенности зачастую бывает разумным начать раскладывать их по разным файлам. Так навигация по ним останется простой, а компоненты станет легче использовать повторно. @@ -14,7 +14,7 @@ title: Импорт и экспорт компонентов * Как импортировать и экспортировать компонент * Когда использовать дефолтные и именованные импорты и экспорты * Как импортировать и экспортировать несколько компонентов из одного файла -* Как разделять компоненты на отдельные файлы +* Как разделять код компонентов на отдельные файлы From aa88d8a7766dcceb17cfe7abb53bad7687afede3 Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Wed, 3 May 2023 22:16:52 +0100 Subject: [PATCH 117/233] Canaries blog post --- src/content/blog/2023/05/03/react-canaries.md | 92 +++++++++++++++++++ src/content/blog/index.md | 5 + src/content/community/versioning-policy.md | 17 ++-- src/sidebarBlog.json | 7 ++ 4 files changed, 115 insertions(+), 6 deletions(-) create mode 100644 src/content/blog/2023/05/03/react-canaries.md diff --git a/src/content/blog/2023/05/03/react-canaries.md b/src/content/blog/2023/05/03/react-canaries.md new file mode 100644 index 000000000..2553255d5 --- /dev/null +++ b/src/content/blog/2023/05/03/react-canaries.md @@ -0,0 +1,92 @@ +--- +title: "React Canaries: Enabling Incremental Feature Rollout Outside Meta" +--- + +May 3, 2023 by [Dan Abramov](https://twitter.com/dan_abramov), [Sophie Alpert](https://twitter.com/sophiebits), [Rick Hanlon](https://twitter.com/rickhanlonii), [Sebastian Markbåge](https://twitter.com/sebmarkbage), and [Andrew Clark](https://twitter.com/acdlite) + +--- + + + +Traditionally, new React features used to only be available at Meta first, and land in the open source releases later. We'd like to offer the React community an option to adopt individual new features as soon as their design is close to final--similar to how Meta uses React internally. We are introducing a new officially supported [Canary release channel](/community/versioning-policy#canary-channel). It lets curated setups like frameworks decouple adoption of individual React features from the React release schedule. + + + +--- + +## tl;dr {/*tldr*/} + +* We're introducing an officially supported [Canary release channel](/community/versioning-policy#canary-channel) for React. +* Canaries let you start using individual new React features before they land in the semver-stable releases. +* Unlike the [Experimental](/community/versioning-policy#experimental-channel) channel, React Canaries only include features that we reasonably believe to be ready for adoption. We encourage frameworks to consider bundling pinned Canary React releases. +* We will announce breaking changes and new features on our blog as they land in Canary releases. +* **As always, React continues to follow semver for every Stable release.** + +## How React features are usually developed {/*how-react-features-are-usually-developed*/} + +Typically, every React feature goes through the same stages: + +1. We develop an initial version and prefix it with `experimental_` or `unstable_`. The feature is only available in the `experimental` release channel and at Meta. At this point, the feature is expected to change significantly. +2. We find a team at Meta willing to help us test this feature and provide feedback on it. This leads to a round of changes. As the feature becomes more stable, we work with more teams at Meta to try it out. +3. Eventually, we feel confident in the design. We remove the prefix from the API name, and make the feature available on the `main` branch by default. At this point, any team at Meta can use this feature. +4. When we are close to cutting an open source release, we post an RFC for the new feature. At this point we are confident the design works for a broad set of cases, but we might make some last minute adjustments. +5. Finally, we release the feature together with its documentation in a stable React release. + +This playbook works well for most features we've released so far. However, there can be a significant gap between when the feature is generally ready to use (step 3) and when it is released in open source (step 5). + +**We'd like to offer the React community an option to follow the same approach as Meta, and adopt individual new features earlier (as they become available) without having to wait for the next release cycle of React.** + +As always, all React features will eventually make it into a Stable release. + +## Can we just do more minor releases? {/*can-we-just-do-more-minor-releases*/} + +Generally, we *do* use minor releases for introducing new features. + +However, this isn't always possible. Sometimes, new features are interconnected with *other* new features which have not yet been fully completed and that we're still actively iterating on. We can't release them separately because their implementations are related. We can't version them separately because they affect the same packages (for example, `react` and `react-dom`). And we need to keep the ability to iterate on the pieces that aren't ready without a flurry of major version releases, which semver would require us to do. + +At Meta, we've solved this problem by building React from the `main` branch, and manually updating it to a specific pinned commit every week. This is also the approach that React Native releases have been following for the last several years. Every *stable* release of React Native is pinned to a specific commit from the `main` branch of the React repository. This lets React Native include important bugfixes and incrementally adopt new React features at the framework level without getting coupled to the global React release schedule. + +We would like to make this workflow available to other frameworks and curated setups. For example, it lets a framework *on top of* React include a React-related breaking change *before* this breaking change gets included into a stable React release. This is particularly useful because some breaking changes only affect framework integrations. This lets a framework release such a change in its own minor version without breaking semver. + +## Why not use experimental releases instead? {/*why-not-use-experimental-releases-instead*/} + +Although you *can* technically use [Experimental releases](/community/versioning-policy#canary-channel), we recommend against using them in production because they can contain significant unannounced breaking changes, or be completely broken. While Canaries can also contain mistakes (as with any release), going forward we plan to announce any significant breaking changes in Canaries on our blog. Canaries are the closest to the code we run internally, so you can generally expect them to be relatively stable. However, you *do* need to keep the version pinned and manually scan the GitHub commit log when updating between the pinned commits. + +**We expect that most people using React outside a curated setup (like a framework) will want to continue using the Stable releases.** However, if you're building a framework, you might want to consider bundling a Canary version of React pinned to a particular commit, and update it at your own pace. The benefit of that is that it lets you ship individual completed React features and bugfixes earlier for your users and at your own release schedule, similar to how React Native has been doing it for the last few years. The downside is that you would take on additional responsibility to communicate which React changes are included with your releases. + +If you're a framework author and want to try this approach, please get in touch with us. + +## Announcing breaking changes and new features early {/*announcing-breaking-changes-and-new-features-early*/} + +Canary releases represent our best guess of what will go into the next stable React release at any given time. + +Traditionally, we've only announced breaking changes at the *end* of the release cycle (when doing a major release). Now that Canary releases are an officially supported way to consume React, we plan to shift towards announcing breaking changes and significant new features *as they land* in Canaries. For example, if we merge a breaking change that will go out in a Canary, we will write a post about it on the React blog, including codemods and migration instructions if necessary. Then, if you're a framework author cutting a major release that updates the pinned React canary to include that change, you can link to our blog post from your release notes. Finally, when a stable major version of React is ready, we will link to those already published blog posts. + +We plan to document APIs as they land in Canaries--even if these APIs are not yet available outside of them. APIs that are only available in Canaries will be marked with a special note on the corresponding pages. This will include APIs like [`use`](https://github.com/reactjs/rfcs/pull/229), and some others (like `cache` and `createServerContext`) which we'll send RFCs for. + +## Canaries must be pinned {/*canaries-must-be-pinned*/} + +If you decide to adopt the Canary workflow for your app or framework, make sure you always pin the *exact* version of the Canary you're using. Since Canaries are pre-releases, they may still include breaking changes. + +## Example: React Server Components {/*example-react-server-components*/} + +As we [announced in March](/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023#react-server-components), the React Server Components conventions have been finalized, and we do not expect significant breaking changes related to their user-facing API contract. However, we can't release support for React Server Components in a stable version of React yet because we are still working on several intertwined framework-only features (such as [asset loading](/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023#asset-loading)) and expect more breaking changes there. + +This means that React Server Components are ready to be adopted by frameworks. However, until the next major React release, the only way for a framework to adopt them is to ship a pinned Canary version of React. (To avoid bundling two copies of React, frameworks that wish to do this would need to enforce resolution of `react` and `react-dom` to the pinned Canary they ship with their framework, and explain that to their users.) + +## Testing libraries against both Stable and Canary versions {/*testing-libraries-against-both-stable-and-canary-versions*/} + +We do not expect library authors to test every single Canary release since it would be prohibitively difficult. However, just as when we [originally introduced the different React pre-release channels three years ago](https://legacy.reactjs.org/blog/2019/10/22/react-release-channels.html), we encourage libraries to run tests against *both* the latest Stable and latest Canary versions. If you see a change in behavior that wasn't announced, please file a bug in the React repository so that we can help diagnose it. We expect that as this practice becomes widely adopted, it will reduce the amount of effort necessary to upgrade libraries to new major versions of React, since accidental regressions would be found as they land. + + + +Strictly speaking, Canary is not a *new* release channel--it used to be called Next. However, we've decided to rename it to avoid confusion with Next.js. We're announcing it as a *new* release channel to communicate the new expectations, such as Canaries being an officially supported way to use React. + + + +## Stable releases work like before {/*stable-releases-work-like-before*/} + +We are not introducing any changes to stable React releases. + + + diff --git a/src/content/blog/index.md b/src/content/blog/index.md index 3459965f6..fc8a2969b 100644 --- a/src/content/blog/index.md +++ b/src/content/blog/index.md @@ -10,6 +10,11 @@ This blog is the official source for the updates from the React team. Anything i
            + + +Traditionally, new React features used to only be available at Meta first, and land in the open source releases later. We'd like to offer the React community an option to adopt individual new features as soon as their design is close to final--similar to how Meta uses React internally. We are introducing a new officially supported Canary release channel. It lets curated setups like frameworks decouple adoption of individual React features from the React release schedule. + + diff --git a/src/content/community/versioning-policy.md b/src/content/community/versioning-policy.md index df3a730c7..68d5b8eb1 100644 --- a/src/content/community/versioning-policy.md +++ b/src/content/community/versioning-policy.md @@ -79,13 +79,18 @@ This section will be most relevant to developers who work on frameworks, librari Each of React's release channels is designed for a distinct use case: -- [**Latest**](#latest-channel) is for stable, semver React releases. It's what you get when you install React from npm. This is the channel you're already using today. **Use this for all user-facing React applications.** -- [**Canary**](#canary-channel) tracks the main branch of the React source code repository. Think of these as release candidates for the next minor semver release. Use this for integration testing between React and third party projects. +- [**Latest**](#latest-channel) is for stable, semver React releases. It's what you get when you install React from npm. This is the channel you're already using today. **User-facing applications that consume React directly use this channel.** +- [**Canary**](#canary-channel) tracks the main branch of the React source code repository. Think of these as release candidates for the next semver release. **[Frameworks or other curated setups may choose to use this channel with a pinned version of React.](/blog/2023/05/03/react-canaries) You can also Canaries for integration testing between React and third party projects.** - [**Experimental**](#experimental-channel) includes experimental APIs and features that aren't available in the stable releases. These also track the main branch, but with additional feature flags turned on. Use this to try out upcoming features before they are released. All releases are published to npm, but only Latest uses semantic versioning. Prereleases (those in the Canary and Experimental channels) have versions generated from a hash of their contents and the commit date, e.g. `18.3.0-canary-388686f29-20230503` for Canary and `0.0.0-experimental-388686f29-20230503` for Experimental. -**The only officially supported release channel for user-facing applications is Latest**. Canary and Experimental releases are provided for testing purposes only, and we provide no guarantees that behavior won't change between releases. They do not follow the semver protocol that we use for releases from Latest. +**Both Latest and Canary channels are officially supported for user-facing applications, but with different expectations**: + +* Latest releases follow the traditional semver model. +* Canary releases [must be pinned](/blog/2023/05/03/react-canaries) and may include breaking changes. They exist for curated setups (like frameworks) that want to gradually release new React features and bugfixes on their own release schedule. + +The Experimental releases are provided for testing purposes only, and we provide no guarantees that behavior won't change between releases. They do not follow the semver protocol that we use for releases from Latest. By publishing prereleases to the same registry that we use for stable releases, we are able to take advantage of the many tools that support the npm workflow, like [unpkg](https://unpkg.com) and [CodeSandbox](https://codesandbox.io). @@ -93,7 +98,7 @@ By publishing prereleases to the same registry that we use for stable releases, Latest is the channel used for stable React releases. It corresponds to the `latest` tag on npm. It is the recommended channel for all React apps that are shipped to real users. -**If you're not sure which channel you should use, it's Latest.** If you're a React developer, this is what you're already using. You can expect updates to Latest to be extremely stable. Versions follow the semantic versioning scheme, as [described earlier.](#stable-releases) +**If you're not sure which channel you should use, it's Latest.** If you're using React directly, this is what you're already using. You can expect updates to Latest to be extremely stable. Versions follow the semantic versioning scheme, as [described earlier.](#stable-releases) ### Canary channel {/*canary-channel*/} @@ -101,13 +106,13 @@ The Canary channel is a prerelease channel that tracks the main branch of the Re The degree of change between the most recent Canary release and the most recent Latest release is approximately the same as you would find between two minor semver releases. However, **the Canary channel does not conform to semantic versioning.** You should expect occasional breaking changes between successive releases in the Canary channel. -**Do not use prereleases in user-facing applications.** +**Do not use prereleases in user-facing applications directly unless you're following the [Canary workflow](/blog/2023/05/03/react-canaries).** Releases in Canary are published with the `canary` tag on npm. Versions are generated from a hash of the build's contents and the commit date, e.g. `18.3.0-canary-388686f29-20230503`. #### Using the canary channel for integration testing {/*using-the-canary-channel-for-integration-testing*/} -The Canary channel is designed to support integration testing between React and other projects. +The Canary channel also supports integration testing between React and other projects. All changes to React go through extensive internal testing before they are released to the public. However, there are a myriad of environments and configurations used throughout the React ecosystem, and it's not possible for us to test against every single one. diff --git a/src/sidebarBlog.json b/src/sidebarBlog.json index d6258e4a2..2141181b0 100644 --- a/src/sidebarBlog.json +++ b/src/sidebarBlog.json @@ -11,6 +11,13 @@ "path": "/blog", "skipBreadcrumb": true, "routes": [ + { + "title": "React Canaries: Enabling Incremental Feature Rollout Outside Meta", + "titleForHomepage": "React Canaries: Incremental Feature Rollout", + "icon": "blog", + "date": "May 3, 2023", + "path": "/blog/2023/05/03/react-canaries" + }, { "title": "React Labs: What We've Been Working On – March 2023", "titleForHomepage": "React Labs: March 2023", From 9a865fd5159b323c4c3e4c74b52e1bf720b36488 Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Wed, 3 May 2023 22:18:00 +0100 Subject: [PATCH 118/233] Revert "Canaries blog post" This reverts commit aa88d8a7766dcceb17cfe7abb53bad7687afede3. --- src/content/blog/2023/05/03/react-canaries.md | 92 ------------------- src/content/blog/index.md | 5 - src/content/community/versioning-policy.md | 17 ++-- src/sidebarBlog.json | 7 -- 4 files changed, 6 insertions(+), 115 deletions(-) delete mode 100644 src/content/blog/2023/05/03/react-canaries.md diff --git a/src/content/blog/2023/05/03/react-canaries.md b/src/content/blog/2023/05/03/react-canaries.md deleted file mode 100644 index 2553255d5..000000000 --- a/src/content/blog/2023/05/03/react-canaries.md +++ /dev/null @@ -1,92 +0,0 @@ ---- -title: "React Canaries: Enabling Incremental Feature Rollout Outside Meta" ---- - -May 3, 2023 by [Dan Abramov](https://twitter.com/dan_abramov), [Sophie Alpert](https://twitter.com/sophiebits), [Rick Hanlon](https://twitter.com/rickhanlonii), [Sebastian Markbåge](https://twitter.com/sebmarkbage), and [Andrew Clark](https://twitter.com/acdlite) - ---- - - - -Traditionally, new React features used to only be available at Meta first, and land in the open source releases later. We'd like to offer the React community an option to adopt individual new features as soon as their design is close to final--similar to how Meta uses React internally. We are introducing a new officially supported [Canary release channel](/community/versioning-policy#canary-channel). It lets curated setups like frameworks decouple adoption of individual React features from the React release schedule. - - - ---- - -## tl;dr {/*tldr*/} - -* We're introducing an officially supported [Canary release channel](/community/versioning-policy#canary-channel) for React. -* Canaries let you start using individual new React features before they land in the semver-stable releases. -* Unlike the [Experimental](/community/versioning-policy#experimental-channel) channel, React Canaries only include features that we reasonably believe to be ready for adoption. We encourage frameworks to consider bundling pinned Canary React releases. -* We will announce breaking changes and new features on our blog as they land in Canary releases. -* **As always, React continues to follow semver for every Stable release.** - -## How React features are usually developed {/*how-react-features-are-usually-developed*/} - -Typically, every React feature goes through the same stages: - -1. We develop an initial version and prefix it with `experimental_` or `unstable_`. The feature is only available in the `experimental` release channel and at Meta. At this point, the feature is expected to change significantly. -2. We find a team at Meta willing to help us test this feature and provide feedback on it. This leads to a round of changes. As the feature becomes more stable, we work with more teams at Meta to try it out. -3. Eventually, we feel confident in the design. We remove the prefix from the API name, and make the feature available on the `main` branch by default. At this point, any team at Meta can use this feature. -4. When we are close to cutting an open source release, we post an RFC for the new feature. At this point we are confident the design works for a broad set of cases, but we might make some last minute adjustments. -5. Finally, we release the feature together with its documentation in a stable React release. - -This playbook works well for most features we've released so far. However, there can be a significant gap between when the feature is generally ready to use (step 3) and when it is released in open source (step 5). - -**We'd like to offer the React community an option to follow the same approach as Meta, and adopt individual new features earlier (as they become available) without having to wait for the next release cycle of React.** - -As always, all React features will eventually make it into a Stable release. - -## Can we just do more minor releases? {/*can-we-just-do-more-minor-releases*/} - -Generally, we *do* use minor releases for introducing new features. - -However, this isn't always possible. Sometimes, new features are interconnected with *other* new features which have not yet been fully completed and that we're still actively iterating on. We can't release them separately because their implementations are related. We can't version them separately because they affect the same packages (for example, `react` and `react-dom`). And we need to keep the ability to iterate on the pieces that aren't ready without a flurry of major version releases, which semver would require us to do. - -At Meta, we've solved this problem by building React from the `main` branch, and manually updating it to a specific pinned commit every week. This is also the approach that React Native releases have been following for the last several years. Every *stable* release of React Native is pinned to a specific commit from the `main` branch of the React repository. This lets React Native include important bugfixes and incrementally adopt new React features at the framework level without getting coupled to the global React release schedule. - -We would like to make this workflow available to other frameworks and curated setups. For example, it lets a framework *on top of* React include a React-related breaking change *before* this breaking change gets included into a stable React release. This is particularly useful because some breaking changes only affect framework integrations. This lets a framework release such a change in its own minor version without breaking semver. - -## Why not use experimental releases instead? {/*why-not-use-experimental-releases-instead*/} - -Although you *can* technically use [Experimental releases](/community/versioning-policy#canary-channel), we recommend against using them in production because they can contain significant unannounced breaking changes, or be completely broken. While Canaries can also contain mistakes (as with any release), going forward we plan to announce any significant breaking changes in Canaries on our blog. Canaries are the closest to the code we run internally, so you can generally expect them to be relatively stable. However, you *do* need to keep the version pinned and manually scan the GitHub commit log when updating between the pinned commits. - -**We expect that most people using React outside a curated setup (like a framework) will want to continue using the Stable releases.** However, if you're building a framework, you might want to consider bundling a Canary version of React pinned to a particular commit, and update it at your own pace. The benefit of that is that it lets you ship individual completed React features and bugfixes earlier for your users and at your own release schedule, similar to how React Native has been doing it for the last few years. The downside is that you would take on additional responsibility to communicate which React changes are included with your releases. - -If you're a framework author and want to try this approach, please get in touch with us. - -## Announcing breaking changes and new features early {/*announcing-breaking-changes-and-new-features-early*/} - -Canary releases represent our best guess of what will go into the next stable React release at any given time. - -Traditionally, we've only announced breaking changes at the *end* of the release cycle (when doing a major release). Now that Canary releases are an officially supported way to consume React, we plan to shift towards announcing breaking changes and significant new features *as they land* in Canaries. For example, if we merge a breaking change that will go out in a Canary, we will write a post about it on the React blog, including codemods and migration instructions if necessary. Then, if you're a framework author cutting a major release that updates the pinned React canary to include that change, you can link to our blog post from your release notes. Finally, when a stable major version of React is ready, we will link to those already published blog posts. - -We plan to document APIs as they land in Canaries--even if these APIs are not yet available outside of them. APIs that are only available in Canaries will be marked with a special note on the corresponding pages. This will include APIs like [`use`](https://github.com/reactjs/rfcs/pull/229), and some others (like `cache` and `createServerContext`) which we'll send RFCs for. - -## Canaries must be pinned {/*canaries-must-be-pinned*/} - -If you decide to adopt the Canary workflow for your app or framework, make sure you always pin the *exact* version of the Canary you're using. Since Canaries are pre-releases, they may still include breaking changes. - -## Example: React Server Components {/*example-react-server-components*/} - -As we [announced in March](/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023#react-server-components), the React Server Components conventions have been finalized, and we do not expect significant breaking changes related to their user-facing API contract. However, we can't release support for React Server Components in a stable version of React yet because we are still working on several intertwined framework-only features (such as [asset loading](/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023#asset-loading)) and expect more breaking changes there. - -This means that React Server Components are ready to be adopted by frameworks. However, until the next major React release, the only way for a framework to adopt them is to ship a pinned Canary version of React. (To avoid bundling two copies of React, frameworks that wish to do this would need to enforce resolution of `react` and `react-dom` to the pinned Canary they ship with their framework, and explain that to their users.) - -## Testing libraries against both Stable and Canary versions {/*testing-libraries-against-both-stable-and-canary-versions*/} - -We do not expect library authors to test every single Canary release since it would be prohibitively difficult. However, just as when we [originally introduced the different React pre-release channels three years ago](https://legacy.reactjs.org/blog/2019/10/22/react-release-channels.html), we encourage libraries to run tests against *both* the latest Stable and latest Canary versions. If you see a change in behavior that wasn't announced, please file a bug in the React repository so that we can help diagnose it. We expect that as this practice becomes widely adopted, it will reduce the amount of effort necessary to upgrade libraries to new major versions of React, since accidental regressions would be found as they land. - - - -Strictly speaking, Canary is not a *new* release channel--it used to be called Next. However, we've decided to rename it to avoid confusion with Next.js. We're announcing it as a *new* release channel to communicate the new expectations, such as Canaries being an officially supported way to use React. - - - -## Stable releases work like before {/*stable-releases-work-like-before*/} - -We are not introducing any changes to stable React releases. - - - diff --git a/src/content/blog/index.md b/src/content/blog/index.md index fc8a2969b..3459965f6 100644 --- a/src/content/blog/index.md +++ b/src/content/blog/index.md @@ -10,11 +10,6 @@ This blog is the official source for the updates from the React team. Anything i
            - - -Traditionally, new React features used to only be available at Meta first, and land in the open source releases later. We'd like to offer the React community an option to adopt individual new features as soon as their design is close to final--similar to how Meta uses React internally. We are introducing a new officially supported Canary release channel. It lets curated setups like frameworks decouple adoption of individual React features from the React release schedule. - - diff --git a/src/content/community/versioning-policy.md b/src/content/community/versioning-policy.md index 68d5b8eb1..df3a730c7 100644 --- a/src/content/community/versioning-policy.md +++ b/src/content/community/versioning-policy.md @@ -79,18 +79,13 @@ This section will be most relevant to developers who work on frameworks, librari Each of React's release channels is designed for a distinct use case: -- [**Latest**](#latest-channel) is for stable, semver React releases. It's what you get when you install React from npm. This is the channel you're already using today. **User-facing applications that consume React directly use this channel.** -- [**Canary**](#canary-channel) tracks the main branch of the React source code repository. Think of these as release candidates for the next semver release. **[Frameworks or other curated setups may choose to use this channel with a pinned version of React.](/blog/2023/05/03/react-canaries) You can also Canaries for integration testing between React and third party projects.** +- [**Latest**](#latest-channel) is for stable, semver React releases. It's what you get when you install React from npm. This is the channel you're already using today. **Use this for all user-facing React applications.** +- [**Canary**](#canary-channel) tracks the main branch of the React source code repository. Think of these as release candidates for the next minor semver release. Use this for integration testing between React and third party projects. - [**Experimental**](#experimental-channel) includes experimental APIs and features that aren't available in the stable releases. These also track the main branch, but with additional feature flags turned on. Use this to try out upcoming features before they are released. All releases are published to npm, but only Latest uses semantic versioning. Prereleases (those in the Canary and Experimental channels) have versions generated from a hash of their contents and the commit date, e.g. `18.3.0-canary-388686f29-20230503` for Canary and `0.0.0-experimental-388686f29-20230503` for Experimental. -**Both Latest and Canary channels are officially supported for user-facing applications, but with different expectations**: - -* Latest releases follow the traditional semver model. -* Canary releases [must be pinned](/blog/2023/05/03/react-canaries) and may include breaking changes. They exist for curated setups (like frameworks) that want to gradually release new React features and bugfixes on their own release schedule. - -The Experimental releases are provided for testing purposes only, and we provide no guarantees that behavior won't change between releases. They do not follow the semver protocol that we use for releases from Latest. +**The only officially supported release channel for user-facing applications is Latest**. Canary and Experimental releases are provided for testing purposes only, and we provide no guarantees that behavior won't change between releases. They do not follow the semver protocol that we use for releases from Latest. By publishing prereleases to the same registry that we use for stable releases, we are able to take advantage of the many tools that support the npm workflow, like [unpkg](https://unpkg.com) and [CodeSandbox](https://codesandbox.io). @@ -98,7 +93,7 @@ By publishing prereleases to the same registry that we use for stable releases, Latest is the channel used for stable React releases. It corresponds to the `latest` tag on npm. It is the recommended channel for all React apps that are shipped to real users. -**If you're not sure which channel you should use, it's Latest.** If you're using React directly, this is what you're already using. You can expect updates to Latest to be extremely stable. Versions follow the semantic versioning scheme, as [described earlier.](#stable-releases) +**If you're not sure which channel you should use, it's Latest.** If you're a React developer, this is what you're already using. You can expect updates to Latest to be extremely stable. Versions follow the semantic versioning scheme, as [described earlier.](#stable-releases) ### Canary channel {/*canary-channel*/} @@ -106,13 +101,13 @@ The Canary channel is a prerelease channel that tracks the main branch of the Re The degree of change between the most recent Canary release and the most recent Latest release is approximately the same as you would find between two minor semver releases. However, **the Canary channel does not conform to semantic versioning.** You should expect occasional breaking changes between successive releases in the Canary channel. -**Do not use prereleases in user-facing applications directly unless you're following the [Canary workflow](/blog/2023/05/03/react-canaries).** +**Do not use prereleases in user-facing applications.** Releases in Canary are published with the `canary` tag on npm. Versions are generated from a hash of the build's contents and the commit date, e.g. `18.3.0-canary-388686f29-20230503`. #### Using the canary channel for integration testing {/*using-the-canary-channel-for-integration-testing*/} -The Canary channel also supports integration testing between React and other projects. +The Canary channel is designed to support integration testing between React and other projects. All changes to React go through extensive internal testing before they are released to the public. However, there are a myriad of environments and configurations used throughout the React ecosystem, and it's not possible for us to test against every single one. diff --git a/src/sidebarBlog.json b/src/sidebarBlog.json index 2141181b0..d6258e4a2 100644 --- a/src/sidebarBlog.json +++ b/src/sidebarBlog.json @@ -11,13 +11,6 @@ "path": "/blog", "skipBreadcrumb": true, "routes": [ - { - "title": "React Canaries: Enabling Incremental Feature Rollout Outside Meta", - "titleForHomepage": "React Canaries: Incremental Feature Rollout", - "icon": "blog", - "date": "May 3, 2023", - "path": "/blog/2023/05/03/react-canaries" - }, { "title": "React Labs: What We've Been Working On – March 2023", "titleForHomepage": "React Labs: March 2023", From 69ca3dfda09b7f36dbb3e668d3267f32ee7e4eb0 Mon Sep 17 00:00:00 2001 From: Elton Maiyo Date: Thu, 4 May 2023 00:20:43 +0300 Subject: [PATCH 119/233] Fixes grammar (#5967) --- src/content/learn/state-as-a-snapshot.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/state-as-a-snapshot.md b/src/content/learn/state-as-a-snapshot.md index adf61e807..503b0abb4 100644 --- a/src/content/learn/state-as-a-snapshot.md +++ b/src/content/learn/state-as-a-snapshot.md @@ -327,7 +327,7 @@ But what if you wanted to read the latest state before a re-render? You'll want #### Implement a traffic light {/*implement-a-traffic-light*/} -Here is a crosswalk light component that toggles on when the button is pressed: +Here is a crosswalk light component that toggles when the button is pressed: From 1c55fe8a44616f5ae6eac23915eb5865576a0245 Mon Sep 17 00:00:00 2001 From: dan Date: Wed, 3 May 2023 23:07:50 +0100 Subject: [PATCH 120/233] Canaries blog post (#5993) * Revert "Revert "Canaries blog post"" This reverts commit 9a865fd5159b323c4c3e4c74b52e1bf720b36488. * words --------- Co-authored-by: Sophie Alpert --- src/content/blog/2023/05/03/react-canaries.md | 94 +++++++++++++++++++ src/content/blog/index.md | 5 + src/content/community/versioning-policy.md | 17 ++-- src/sidebarBlog.json | 7 ++ 4 files changed, 117 insertions(+), 6 deletions(-) create mode 100644 src/content/blog/2023/05/03/react-canaries.md diff --git a/src/content/blog/2023/05/03/react-canaries.md b/src/content/blog/2023/05/03/react-canaries.md new file mode 100644 index 000000000..00b725cc7 --- /dev/null +++ b/src/content/blog/2023/05/03/react-canaries.md @@ -0,0 +1,94 @@ +--- +title: "React Canaries: Enabling Incremental Feature Rollout Outside Meta" +--- + +May 3, 2023 by [Dan Abramov](https://twitter.com/dan_abramov), [Sophie Alpert](https://twitter.com/sophiebits), [Rick Hanlon](https://twitter.com/rickhanlonii), [Sebastian Markbåge](https://twitter.com/sebmarkbage), and [Andrew Clark](https://twitter.com/acdlite) + +--- + + + +Traditionally, Meta has run a bleeding-edge version of React in order to test new React features before they're released in a stable version. We'd like to offer the React community an option to adopt individual new features as soon as their design is close to final--similar to how Meta has used React internally. We are introducing a new officially supported [Canary release channel](/community/versioning-policy#canary-channel). It lets curated setups like frameworks decouple adoption of individual React features from the React release schedule. + + + +--- + +## tl;dr {/*tldr*/} + +* We're introducing an officially supported [Canary release channel](/community/versioning-policy#canary-channel) for React. Since it's officially supported, if any regressions land, we'll treat them with a similar urgency to bugs in stable releases. +* Canaries let you start using individual new React features before they land in the semver-stable releases. +* Unlike the [Experimental](/community/versioning-policy#experimental-channel) channel, React Canaries only include features that we reasonably believe to be ready for adoption. We encourage frameworks to consider bundling pinned Canary React releases. +* We will announce breaking changes and new features on our blog as they land in Canary releases. +* **As always, React continues to follow semver for every Stable release.** + +## How React features are usually developed {/*how-react-features-are-usually-developed*/} + +Typically, every React feature has gone through the same stages: + +1. We develop an initial version and prefix it with `experimental_` or `unstable_`. The feature is only available in the `experimental` release channel. At this point, the feature is expected to change significantly. +2. We find a team at Meta willing to help us test this feature and provide feedback on it. This leads to a round of changes. As the feature becomes more stable, we work with more teams at Meta to try it out. +3. Eventually, we feel confident in the design. We remove the prefix from the API name, and make the feature available on the `main` branch by default, which most Meta products use. At this point, any team at Meta can use this feature. +4. As we build confidence in the direction, we also post an RFC for the new feature. At this point we know the design works for a broad set of cases, but we might make some last minute adjustments. +5. When we are close to cutting an open source release, we write documentation for the feature and finally release the feature in a stable React release. + +This playbook works well for most features we've released so far. However, there can be a significant gap between when the feature is generally ready to use (step 3) and when it is released in open source (step 5). + +**We'd like to offer the React community an option to follow the same approach as Meta, and adopt individual new features earlier (as they become available) without having to wait for the next release cycle of React.** + +As always, all React features will eventually make it into a Stable release. + +## Can we just do more minor releases? {/*can-we-just-do-more-minor-releases*/} + +Generally, we *do* use minor releases for introducing new features. + +However, this isn't always possible. Sometimes, new features are interconnected with *other* new features which have not yet been fully completed and that we're still actively iterating on. We can't release them separately because their implementations are related. We can't version them separately because they affect the same packages (for example, `react` and `react-dom`). And we need to keep the ability to iterate on the pieces that aren't ready without a flurry of major version releases, which semver would require us to do. + +At Meta, we've solved this problem by building React from the `main` branch, and manually updating it to a specific pinned commit every week. This is also the approach that React Native releases have been following for the last several years. Every *stable* release of React Native is pinned to a specific commit from the `main` branch of the React repository. This lets React Native include important bugfixes and incrementally adopt new React features at the framework level without getting coupled to the global React release schedule. + +We would like to make this workflow available to other frameworks and curated setups. For example, it lets a framework *on top of* React include a React-related breaking change *before* this breaking change gets included into a stable React release. This is particularly useful because some breaking changes only affect framework integrations. This lets a framework release such a change in its own minor version without breaking semver. + +Rolling releases with the Canaries channel will allow us to have a tighter feedback loop and ensure that new features get comprehensive testing in the community. This workflow is closer to how TC39, the JavaScript standards committee, [handles changes in numbered stages](https://tc39.es/process-document/). New React features may be available in frameworks built on React before they are in a React stable release, just as new JavaScript features ship in browsers before they are officially ratified as part of the specification. + +## Why not use experimental releases instead? {/*why-not-use-experimental-releases-instead*/} + +Although you *can* technically use [Experimental releases](/community/versioning-policy#canary-channel), we recommend against using them in production because experimental APIs can undergo significant breaking changes on their way to stabilization (or can even be removed entirely). While Canaries can also contain mistakes (as with any release), going forward we plan to announce any significant breaking changes in Canaries on our blog. Canaries are the closest to the code Meta runs internally, so you can generally expect them to be relatively stable. However, you *do* need to keep the version pinned and manually scan the GitHub commit log when updating between the pinned commits. + +**We expect that most people using React outside a curated setup (like a framework) will want to continue using the Stable releases.** However, if you're building a framework, you might want to consider bundling a Canary version of React pinned to a particular commit, and update it at your own pace. The benefit of that is that it lets you ship individual completed React features and bugfixes earlier for your users and at your own release schedule, similar to how React Native has been doing it for the last few years. The downside is that you would take on additional responsibility to review which React commits are being pulled in and communicate to your users which React changes are included with your releases. + +If you're a framework author and want to try this approach, please get in touch with us. + +## Announcing breaking changes and new features early {/*announcing-breaking-changes-and-new-features-early*/} + +Canary releases represent our best guess of what will go into the next stable React release at any given time. + +Traditionally, we've only announced breaking changes at the *end* of the release cycle (when doing a major release). Now that Canary releases are an officially supported way to consume React, we plan to shift towards announcing breaking changes and significant new features *as they land* in Canaries. For example, if we merge a breaking change that will go out in a Canary, we will write a post about it on the React blog, including codemods and migration instructions if necessary. Then, if you're a framework author cutting a major release that updates the pinned React canary to include that change, you can link to our blog post from your release notes. Finally, when a stable major version of React is ready, we will link to those already published blog posts, which we hope will help our team make progress faster. + +We plan to document APIs as they land in Canaries--even if these APIs are not yet available outside of them. APIs that are only available in Canaries will be marked with a special note on the corresponding pages. This will include APIs like [`use`](https://github.com/reactjs/rfcs/pull/229), and some others (like `cache` and `createServerContext`) which we'll send RFCs for. + +## Canaries must be pinned {/*canaries-must-be-pinned*/} + +If you decide to adopt the Canary workflow for your app or framework, make sure you always pin the *exact* version of the Canary you're using. Since Canaries are pre-releases, they may still include breaking changes. + +## Example: React Server Components {/*example-react-server-components*/} + +As we [announced in March](/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023#react-server-components), the React Server Components conventions have been finalized, and we do not expect significant breaking changes related to their user-facing API contract. However, we can't release support for React Server Components in a stable version of React yet because we are still working on several intertwined framework-only features (such as [asset loading](/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023#asset-loading)) and expect more breaking changes there. + +This means that React Server Components are ready to be adopted by frameworks. However, until the next major React release, the only way for a framework to adopt them is to ship a pinned Canary version of React. (To avoid bundling two copies of React, frameworks that wish to do this would need to enforce resolution of `react` and `react-dom` to the pinned Canary they ship with their framework, and explain that to their users. As an example, this is what Next.js App Router does.) + +## Testing libraries against both Stable and Canary versions {/*testing-libraries-against-both-stable-and-canary-versions*/} + +We do not expect library authors to test every single Canary release since it would be prohibitively difficult. However, just as when we [originally introduced the different React pre-release channels three years ago](https://legacy.reactjs.org/blog/2019/10/22/react-release-channels.html), we encourage libraries to run tests against *both* the latest Stable and latest Canary versions. If you see a change in behavior that wasn't announced, please file a bug in the React repository so that we can help diagnose it. We expect that as this practice becomes widely adopted, it will reduce the amount of effort necessary to upgrade libraries to new major versions of React, since accidental regressions would be found as they land. + + + +Strictly speaking, Canary is not a *new* release channel--it used to be called Next. However, we've decided to rename it to avoid confusion with Next.js. We're announcing it as a *new* release channel to communicate the new expectations, such as Canaries being an officially supported way to use React. + + + +## Stable releases work like before {/*stable-releases-work-like-before*/} + +We are not introducing any changes to stable React releases. + + + diff --git a/src/content/blog/index.md b/src/content/blog/index.md index 3459965f6..fc8a2969b 100644 --- a/src/content/blog/index.md +++ b/src/content/blog/index.md @@ -10,6 +10,11 @@ This blog is the official source for the updates from the React team. Anything i
            + + +Traditionally, new React features used to only be available at Meta first, and land in the open source releases later. We'd like to offer the React community an option to adopt individual new features as soon as their design is close to final--similar to how Meta uses React internally. We are introducing a new officially supported Canary release channel. It lets curated setups like frameworks decouple adoption of individual React features from the React release schedule. + + diff --git a/src/content/community/versioning-policy.md b/src/content/community/versioning-policy.md index df3a730c7..68d5b8eb1 100644 --- a/src/content/community/versioning-policy.md +++ b/src/content/community/versioning-policy.md @@ -79,13 +79,18 @@ This section will be most relevant to developers who work on frameworks, librari Each of React's release channels is designed for a distinct use case: -- [**Latest**](#latest-channel) is for stable, semver React releases. It's what you get when you install React from npm. This is the channel you're already using today. **Use this for all user-facing React applications.** -- [**Canary**](#canary-channel) tracks the main branch of the React source code repository. Think of these as release candidates for the next minor semver release. Use this for integration testing between React and third party projects. +- [**Latest**](#latest-channel) is for stable, semver React releases. It's what you get when you install React from npm. This is the channel you're already using today. **User-facing applications that consume React directly use this channel.** +- [**Canary**](#canary-channel) tracks the main branch of the React source code repository. Think of these as release candidates for the next semver release. **[Frameworks or other curated setups may choose to use this channel with a pinned version of React.](/blog/2023/05/03/react-canaries) You can also Canaries for integration testing between React and third party projects.** - [**Experimental**](#experimental-channel) includes experimental APIs and features that aren't available in the stable releases. These also track the main branch, but with additional feature flags turned on. Use this to try out upcoming features before they are released. All releases are published to npm, but only Latest uses semantic versioning. Prereleases (those in the Canary and Experimental channels) have versions generated from a hash of their contents and the commit date, e.g. `18.3.0-canary-388686f29-20230503` for Canary and `0.0.0-experimental-388686f29-20230503` for Experimental. -**The only officially supported release channel for user-facing applications is Latest**. Canary and Experimental releases are provided for testing purposes only, and we provide no guarantees that behavior won't change between releases. They do not follow the semver protocol that we use for releases from Latest. +**Both Latest and Canary channels are officially supported for user-facing applications, but with different expectations**: + +* Latest releases follow the traditional semver model. +* Canary releases [must be pinned](/blog/2023/05/03/react-canaries) and may include breaking changes. They exist for curated setups (like frameworks) that want to gradually release new React features and bugfixes on their own release schedule. + +The Experimental releases are provided for testing purposes only, and we provide no guarantees that behavior won't change between releases. They do not follow the semver protocol that we use for releases from Latest. By publishing prereleases to the same registry that we use for stable releases, we are able to take advantage of the many tools that support the npm workflow, like [unpkg](https://unpkg.com) and [CodeSandbox](https://codesandbox.io). @@ -93,7 +98,7 @@ By publishing prereleases to the same registry that we use for stable releases, Latest is the channel used for stable React releases. It corresponds to the `latest` tag on npm. It is the recommended channel for all React apps that are shipped to real users. -**If you're not sure which channel you should use, it's Latest.** If you're a React developer, this is what you're already using. You can expect updates to Latest to be extremely stable. Versions follow the semantic versioning scheme, as [described earlier.](#stable-releases) +**If you're not sure which channel you should use, it's Latest.** If you're using React directly, this is what you're already using. You can expect updates to Latest to be extremely stable. Versions follow the semantic versioning scheme, as [described earlier.](#stable-releases) ### Canary channel {/*canary-channel*/} @@ -101,13 +106,13 @@ The Canary channel is a prerelease channel that tracks the main branch of the Re The degree of change between the most recent Canary release and the most recent Latest release is approximately the same as you would find between two minor semver releases. However, **the Canary channel does not conform to semantic versioning.** You should expect occasional breaking changes between successive releases in the Canary channel. -**Do not use prereleases in user-facing applications.** +**Do not use prereleases in user-facing applications directly unless you're following the [Canary workflow](/blog/2023/05/03/react-canaries).** Releases in Canary are published with the `canary` tag on npm. Versions are generated from a hash of the build's contents and the commit date, e.g. `18.3.0-canary-388686f29-20230503`. #### Using the canary channel for integration testing {/*using-the-canary-channel-for-integration-testing*/} -The Canary channel is designed to support integration testing between React and other projects. +The Canary channel also supports integration testing between React and other projects. All changes to React go through extensive internal testing before they are released to the public. However, there are a myriad of environments and configurations used throughout the React ecosystem, and it's not possible for us to test against every single one. diff --git a/src/sidebarBlog.json b/src/sidebarBlog.json index d6258e4a2..2141181b0 100644 --- a/src/sidebarBlog.json +++ b/src/sidebarBlog.json @@ -11,6 +11,13 @@ "path": "/blog", "skipBreadcrumb": true, "routes": [ + { + "title": "React Canaries: Enabling Incremental Feature Rollout Outside Meta", + "titleForHomepage": "React Canaries: Incremental Feature Rollout", + "icon": "blog", + "date": "May 3, 2023", + "path": "/blog/2023/05/03/react-canaries" + }, { "title": "React Labs: What We've Been Working On – March 2023", "titleForHomepage": "React Labs: March 2023", From 1863ab2cb585595f39251bb34380d23dbdc0f3bb Mon Sep 17 00:00:00 2001 From: Sophie Alpert Date: Wed, 3 May 2023 15:35:52 -0700 Subject: [PATCH 121/233] tweak --- src/content/blog/2023/05/03/react-canaries.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/blog/2023/05/03/react-canaries.md b/src/content/blog/2023/05/03/react-canaries.md index 00b725cc7..81da3fd00 100644 --- a/src/content/blog/2023/05/03/react-canaries.md +++ b/src/content/blog/2023/05/03/react-canaries.md @@ -8,7 +8,7 @@ May 3, 2023 by [Dan Abramov](https://twitter.com/dan_abramov), [Sophie Alpert](h -Traditionally, Meta has run a bleeding-edge version of React in order to test new React features before they're released in a stable version. We'd like to offer the React community an option to adopt individual new features as soon as their design is close to final--similar to how Meta has used React internally. We are introducing a new officially supported [Canary release channel](/community/versioning-policy#canary-channel). It lets curated setups like frameworks decouple adoption of individual React features from the React release schedule. +We'd like to offer the React community an option to adopt individual new features as soon as their design is close to final, before they're released in a stable version--similar to how Meta has long used bleeding-edge versions of React internally. We are introducing a new officially supported [Canary release channel](/community/versioning-policy#canary-channel). It lets curated setups like frameworks decouple adoption of individual React features from the React release schedule. From 4488d86b4bfeb5c65c32ad7a5043b21e0cb7b8f7 Mon Sep 17 00:00:00 2001 From: Pavel Zenov Date: Thu, 4 May 2023 10:32:46 +0300 Subject: [PATCH 122/233] Apply suggestions from code review Co-authored-by: Nick Tishkevich --- src/content/learn/index.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/content/learn/index.md b/src/content/learn/index.md index e14bdc22e..f80c35d34 100644 --- a/src/content/learn/index.md +++ b/src/content/learn/index.md @@ -22,7 +22,7 @@ title: Quick Start Приложения на React собираются из *компонентов*. Компонент — это часть пользовательского интерфейса, у которого есть собственная логика и внешность. Компонент может быть маленьким, как кнопка, или большим, как целая страница. -Компоненты React — это функции JavaScript, которые возвращают разметку: +React-компоненты — это функции JavaScript, которые возвращают разметку: ```js function MyButton() { @@ -114,7 +114,7 @@ React не ограничивает вас в том, как добавлять ## Отображение данных {/*displaying-data*/} -Фигурные скобки внутри JSX-разметки позволяют использовать JavaScript, например для того чтобы отобразить свою переменную пользователю. Код ниже отобразит `user.name`: +Фигурные скобки внутри JSX-разметки позволяют использовать JavaScript, например, для того, чтобы отобразить свою переменную пользователю. Код ниже отобразит `user.name`: ```js {3} return ( @@ -295,11 +295,11 @@ function MyButton() { } ``` -Заметьте: у `onClick={handleClick}` нет скобок в конце! Не _вызывайте_ функцию обработчика событий: вам нужно просто ее *передать*. React вызовет ваш обработчик событий, когда пользователь кликнет по кнопке. +Заметьте: у `onClick={handleClick}` нет скобок в конце! Не _вызывайте_ функцию обработчика событий: вам нужно просто её *передать*. React вызовет ваш обработчик событий, когда пользователь кликнет по кнопке. ## Обновление экрана {/*updating-the-screen*/} -Вам может понадобиться, чтобы компонент «помнил» какую-то информацию и отображал её. Например, вы хотите посчитать сколько раз была нажата кнопка. Чтобы это сделать, добавьте *состояние* в ваш компонент. +Вам может понадобиться, чтобы компонент «помнил» какую-то информацию и отображал её. Например, вы хотите посчитать сколько раз была нажата кнопка. Для этого добавьте *состояние* в ваш компонент. Сначала импортируйте [`useState`](/reference/react/useState) из React: @@ -317,7 +317,7 @@ function MyButton() { `useState` вернет вам две вещи: текущее состояние (`count`) и функцию (`setCount`), которая обновляет его. Можно именовать их как вам угодно, но такого рода вещи принято называть `[something, setSomething]`. -При первом показе кнопка `count` будет иметь значение `0`, потому что вы передали `0` в `useState()`. Чтобы изменить состояние, вызовите `setCount()` и передайте туда новое значение. Клик на эту кнопку будет увеличивать счётчик: +При первом показе кнопка `count` будет иметь значение `0`, потому что вы передали `0` в `useState()`. Для изменения состояния вызовите `setCount()` и передайте туда новое значение. Клик на эту кнопку будет увеличивать счётчик: ```js {5} function MyButton() { @@ -382,7 +382,7 @@ button { ## Использование хуков {/*using-hooks*/} -Функции, которые начинаются с `use`, называются *хуками*. `useState` — это встроенный в React хук. В [справочнике API](/reference/react) приводятся другие встроенные хуки. Также, вы можете писать свои собственные хуки, совмещая их с уже существующими. +Функции, которые начинаются с `use`, называются *хуками*. `useState` — это встроенный хук в React. В [справочнике API](/reference/react) приводятся другие встроенные хуки. Также, вы можете писать свои собственные хуки, совмещая их с уже существующими. У хуков больше ограничений, чем у других функций. Хуки могут вызываться только *в начале* ваших компонентов (или других хуков). Если вам нужен `useState` в условии или цикле, выделите новый компонент и используйте его там. @@ -392,7 +392,7 @@ button { - + В начале у каждого `MyButton` состояние `count` равно `0` @@ -428,7 +428,7 @@ button { -Теперь, когда вы нажимаете на любую из кнопок, `count` в `MyApp` будет менять своё значение, что в свою очередь повлечёт обновление счётчиков в обоих компонентах `MyButton`. Вот как это можно прописать в коде. +Теперь, когда вы нажимаете на любую из кнопок, `count` в `MyApp` будет менять своё значение, что в свою очередь повлечёт обновление счётчиков в обоих компонентах `MyButton`. Вот как это можно выразить в коде. Сначала *переместите вверх состояние* из `MyButton` в `MyApp`: @@ -489,7 +489,7 @@ function MyButton({ count, onClick }) { } ``` -Когда вы нажимаете на кнопку, срабатывает обработчик `onClick`. В каждой кнопке в качестве значения пропа `onClick` задана функция `handleClick` из `MyApp`, таким образом, исполняется код этой функции. Этот код вызывает `setCount(count + 1)`, тем самым увеличивая переменную состояния `count`. Новое значение `count` передается в качестве пропа каждой кнопке, таким образом все кнопки будут показывать это новое значение. Это называется "подъёмом состояния вверх". Поднимая состояние вверх, вы делаете его общим для всех компонентов. +Когда вы нажимаете на кнопку, срабатывает обработчик `onClick`. В каждой кнопке в качестве значения пропа `onClick` задана функция `handleClick` из `MyApp`, таким образом, исполняется код этой функции. Этот код вызывает `setCount(count + 1)`, тем самым увеличивая переменную состояния `count`. Новое значение `count` передаётся в качестве пропа каждой кнопке, таким образом все кнопки будут показывать это новое значение. Это называется "подъёмом состояния вверх". Поднимая состояние вверх, вы делаете его общим для всех компонентов. From c2c7f12a26ded59002f62fcf1d7c0260cebc4dd5 Mon Sep 17 00:00:00 2001 From: Pavel Zenov Date: Thu, 4 May 2023 10:51:25 +0300 Subject: [PATCH 123/233] Small fixes that I couldn't add via suggestions UI --- src/content/learn/index.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/content/learn/index.md b/src/content/learn/index.md index f80c35d34..56e417998 100644 --- a/src/content/learn/index.md +++ b/src/content/learn/index.md @@ -5,6 +5,7 @@ title: Quick Start Добро пожаловать в документацию React! Эта страница познакомит вас с большинством концепций React, которыми вы будете пользоваться каждый день. + @@ -246,7 +247,7 @@ return ( ); ``` -Обратите внимание, что у `
          5. ` есть атрибут `key`. Для каждого элемента списка вам нужно задавать ключ в виде строки или числа, который позволит однозначно определить этот элемент среди остальных в списке. Обычно этот ключ берется из ваших данных, например, ключом может быть идентификатор из базы данных. React использует информацию о ключах, чтобы понимать, что случилось, если вы добавите, удалите или переупорядочите элементы. +Обратите внимание, что у `
          6. ` есть атрибут `key`. Для каждого элемента списка вам нужно задавать ключ в виде строки или числа, который позволит однозначно отделить этот элемент от остальных в списке. Обычно этот ключ берется из ваших данных, например, это может быть идентификатор из базы данных. React использует эти ключи при добавлении, удалении или изменении порядка элементов. From 113f93150a8cbd833dc9a86b88a542693a977626 Mon Sep 17 00:00:00 2001 From: YashinaAnastasia <83582926+YashinaAnastasia@users.noreply.github.com> Date: Thu, 4 May 2023 15:53:24 +0300 Subject: [PATCH 124/233] =?UTF-8?q?=D1=84=D0=B8=D0=BD=D0=B0=D0=BB=D1=8C?= =?UTF-8?q?=D0=BD=D1=8B=D0=B5=20=D0=BF=D1=80=D0=B0=D0=B2=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/content/reference/react/lazy.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/content/reference/react/lazy.md b/src/content/reference/react/lazy.md index 46dd921a8..248285209 100644 --- a/src/content/reference/react/lazy.md +++ b/src/content/reference/react/lazy.md @@ -31,11 +31,11 @@ const MarkdownPreview = lazy(() => import('./MarkdownPreview.js')); #### Параметры {/*parameters*/} -* `load`: Функция, которая возвращает [Промис](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Promise) или другой *thenable* (объект, в котором определен метод `then`). Вызова `load` не произойдет до тех пор, пока вы не попытайтесь отрендерить возвращённый компонент. После первого вызова `load`, React будет ждать завершения выполнения команды, а затем отрендерит разрешённое значение как React компонент. Возвращенный промис и разрешенное значение Промиса будут кэшированы, `load` больше вызывать не придется. Если промис отклонили, причина этого будет указана в ближайшем Error Boundary. +* `load`: Функция, которая возвращает [Промис](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Promise) или другой *thenable* (объект, в котором определен метод `then`). Вызова `load` не произойдет до тех пор, пока вы не попытайтесь отрендерить возвращённый компонент. После первого вызова `load`, React будет ждать завершения выполнения команды, а затем отрендерит разрешённое значение как React компонент. Возвращённый промис и разрешённое значение Промиса будут кэшированы, `load` больше вызывать не придется. Если промис отклонили, причина этого будет указана в ближайшем Error Boundary. #### Возвращаемое значение {/*returns*/} -`lazy` возвращает React компонент, которые можно отрендерить в вашем дереве. Во время загрузки ленивых компонентов попытки их рендора будут *заморожены.* Используйте [``](/reference/react/Suspense) для отображения индикатора во время загрузки. +`lazy` возвращает React компонент, которые можно отрендерить в вашем дереве. Во время загрузки ленивых компонентов попытки их рендера будут *заморожены.* Используйте [``](/reference/react/Suspense) для отображения индикатора во время загрузки. --- @@ -47,7 +47,7 @@ const MarkdownPreview = lazy(() => import('./MarkdownPreview.js')); #### Возвращаемое значение {/*load-returns*/} -Возвращает [Промис](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Promise) или другой *thenable* (объект, в котором определен метод `then`). В коненом итоге он вернется к действительному React компоненту, например к функции, [`memo`](/reference/react/memo), или [`forwardRef`](/reference/react/forwardRef) компоненту. +Возвращает [Промис](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Promise) или другой *thenable* (объект, в котором определен метод `then`). В конечном итоге он вернётся к действительному React компоненту, например к функции, [`memo`](/reference/react/memo), или [`forwardRef`](/reference/react/forwardRef) компоненту. --- @@ -69,7 +69,7 @@ import { lazy } from 'react'; const MarkdownPreview = lazy(() => import('./MarkdownPreview.js')); ``` -Этот код опирается на [динамический `import()`,](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import) который должен поддержиавться вашим бандлером или фреймворком. +Этот код опирается на [динамический `import()`,](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import) который должен поддерживаться вашим бандлером или фреймворком. Теперь, когда код вашего компонента загружается по запросу, вам также необходимо указать, что должно отображаться во время его загрузки. Это можно сделать путем оборачивания ленивого компонента или его родителя в [``](/reference/react/Suspense) boundary: @@ -80,7 +80,7 @@ const MarkdownPreview = lazy(() => import('./MarkdownPreview.js')); ``` -Например, код для `MarkdownPreview` не загрузится, пока его не попытаются вызвать. Если `MarkdownPreview` еще не загрузился, на его месте отобразится `Loading`. Попробуйте поставить галочку в чекбоксе: +Например, код для `MarkdownPreview` не загрузится, пока его не попытаются вызвать. Если `MarkdownPreview` ещё не загрузился, на его месте отобразится `Loading`. Попробуйте поставить галочку в чекбоксе: @@ -111,7 +111,7 @@ export default function MarkdownEditor() { ); } -// Add a fixed delay so you can see the loading state +// Добавьте фиксированную задержку, чтобы увидеть загрузку function delayForDemo(promise) { return new Promise(resolve => { setTimeout(resolve, 2000); @@ -174,7 +174,7 @@ body { -Это демо загрузится с искуственной задержкой. В следуйщий раз когда вы снимите и поставите галочку, `Preview` будет закэшировано, загрузки не будет. Чтобы снова увидеть загрузку, нужно нажать "Reset" в сэндбоксе. +Это демо загрузится с искусственной задержкой. В следующий раз когда вы снимите и поставите галочку, `Preview` будет закэшировано, загрузки не будет. Чтобы снова увидеть загрузку, нужно нажать "Reset" в сандбоксе. [Узнать об управлении состояниями загрузки с помощью Suspense.](/reference/react/Suspense) @@ -184,13 +184,13 @@ body { ### Состояние моего `lazy` компонента неожиданно сбрасывается {/*my-lazy-components-state-gets-reset-unexpectedly*/} -Не объявляйте `lazy` компоненты *внтури* других компонентов: +Не объявляйте `lazy` компоненты *внутри* других компонентов: ```js {4-5} import { lazy } from 'react'; function Editor() { - // 🔴 Bad: Все состояния сбросятся при ре-рендере + // 🔴 Плохо: Все состояния сбросятся при ре-рендере const MarkdownPreview = lazy(() => import('./MarkdownPreview.js')); // ... } @@ -201,7 +201,7 @@ function Editor() { ```js {3-4} import { lazy } from 'react'; -// ✅ Good: lazy компонент объявлен вне ваших компонентов. +// ✅ Хорошо: lazy компонент объявлен вне ваших компонентов. const MarkdownPreview = lazy(() => import('./MarkdownPreview.js')); function Editor() { From 8e24e40078c71e909096449cf04fea0a31bb1a7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Lorber?= Date: Fri, 5 May 2023 18:01:08 +0200 Subject: [PATCH 125/233] renderToReadableStream => renders a readable web stream (and not a Node.js stream) (#6001) --- .../reference/react-dom/server/renderToReadableStream.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/reference/react-dom/server/renderToReadableStream.md b/src/content/reference/react-dom/server/renderToReadableStream.md index 3f610d65a..d6d5b3264 100644 --- a/src/content/reference/react-dom/server/renderToReadableStream.md +++ b/src/content/reference/react-dom/server/renderToReadableStream.md @@ -26,7 +26,7 @@ This API depends on [Web Streams.](https://developer.mozilla.org/en-US/docs/Web/ ### `renderToReadableStream(reactNode, options?)` {/*rendertoreadablestream*/} -Call `renderToReadableStream` to render your React tree as HTML into a [Node.js Stream.](https://nodejs.org/api/stream.html#writable-streams) +Call `renderToReadableStream` to render your React tree as HTML into a [Readable Web Stream.](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream) ```js import { renderToReadableStream } from 'react-dom/server'; From fe5737bd0328ca7ce69fe432656efd469df6066a Mon Sep 17 00:00:00 2001 From: declval <123750459+declval@users.noreply.github.com> Date: Fri, 5 May 2023 16:01:29 +0000 Subject: [PATCH 126/233] Update Profiler.md (#6000) --- src/content/reference/react/Profiler.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/reference/react/Profiler.md b/src/content/reference/react/Profiler.md index 5bfa3b317..8e149634a 100644 --- a/src/content/reference/react/Profiler.md +++ b/src/content/reference/react/Profiler.md @@ -33,7 +33,7 @@ Wrap a component tree in a `` to measure its rendering performance. #### Props {/*props*/} * `id`: A string identifying the part of the UI you are measuring. -* `onRender`: An [`onRender` callback](#onrender-callback) that React calls it every time components within the profiled tree update. It receives information about what was rendered and how much time it took. +* `onRender`: An [`onRender` callback](#onrender-callback) that React calls every time components within the profiled tree update. It receives information about what was rendered and how much time it took. #### Caveats {/*caveats*/} From 01d44e9a38afff0cbe125cf9b7dea20b8a1ca6fc Mon Sep 17 00:00:00 2001 From: Hernani Fernandes Date: Fri, 5 May 2023 18:06:39 +0200 Subject: [PATCH 127/233] remove cancelled conference 2023 (#5999) --- src/content/community/conferences.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/content/community/conferences.md b/src/content/community/conferences.md index b1860ac0d..792dbeecf 100644 --- a/src/content/community/conferences.md +++ b/src/content/community/conferences.md @@ -60,11 +60,6 @@ August 17 & 18, 2023. Salt Lake City, UT, USA [Website](https://www.reactrally.com/) - [Twitter](https://twitter.com/ReactRally) - [Instagram](https://www.instagram.com/reactrally/) -### React On The Beach 2023 {/*react-on-the-beach-2023*/} -September 07, 2023. Amsterdam, Netherlands (In-person event) - -[Website](https://reactonthebeach.com/) - [Twitter](https://twitter.com/reactonthebeach) - ### React India 2023 {/*react-india-2023*/} Oct 5 - 7, 2023. In-person in Goa, India (hybrid event) + Oct 3 2023 - remote day From 07a3ee594f77cec139fa64258c4b0adb1672a5db Mon Sep 17 00:00:00 2001 From: Jan Kassens Date: Fri, 5 May 2023 13:58:18 -0400 Subject: [PATCH 128/233] Minor tweak to remove implication that mounting can happen only once (#6003) Mounting with Suspense and Offscreen can happen multiple times. This removes some wording that implies a that effects / lifecycle hooks only happen on first mount. --- src/content/reference/react/Component.md | 4 ++-- src/content/reference/react/useEffect.md | 2 +- src/content/reference/react/useInsertionEffect.md | 2 +- src/content/reference/react/useLayoutEffect.md | 6 +----- 4 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/content/reference/react/Component.md b/src/content/reference/react/Component.md index c1b605803..006ade5d8 100644 --- a/src/content/reference/react/Component.md +++ b/src/content/reference/react/Component.md @@ -248,7 +248,7 @@ There is no direct equivalent for `componentDidCatch` in function components yet ### `componentDidMount()` {/*componentdidmount*/} -If you define the `componentDidMount` method, React will call it when your component is first added *(mounted)* to the screen. This is a common place to start data fetching, set up subscriptions, or manipulate the DOM nodes. +If you define the `componentDidMount` method, React will call it when your component is added *(mounted)* to the screen. This is a common place to start data fetching, set up subscriptions, or manipulate the DOM nodes. If you implement `componentDidMount`, you usually need to implement other lifecycle methods to avoid bugs. For example, if `componentDidMount` reads some state or props, you also have to implement [`componentDidUpdate`](#componentdidupdate) to handle their changes, and [`componentWillUnmount`](#componentwillunmount) to clean up whatever `componentDidMount` was doing. @@ -1215,7 +1215,7 @@ We recommend defining components as functions instead of classes. [See how to mi There are a few special methods you can define on your class. -If you define the [`componentDidMount`](#componentdidmount) method, React will call it when your component is first added *(mounted)* to the screen. React will call [`componentDidUpdate`](#componentdidupdate) after your component re-renders due to changed props or state. React will call [`componentWillUnmount`](#componentwillunmount) after your component has been removed *(unmounted)* from the screen. +If you define the [`componentDidMount`](#componentdidmount) method, React will call it when your component is added *(mounted)* to the screen. React will call [`componentDidUpdate`](#componentdidupdate) after your component re-renders due to changed props or state. React will call [`componentWillUnmount`](#componentwillunmount) after your component has been removed *(unmounted)* from the screen. If you implement `componentDidMount`, you usually need to implement all three lifecycles to avoid bugs. For example, if `componentDidMount` reads some state or props, you also have to implement `componentDidUpdate` to handle their changes, and `componentWillUnmount` to clean up whatever `componentDidMount` was doing. diff --git a/src/content/reference/react/useEffect.md b/src/content/reference/react/useEffect.md index bc76bdfbe..8614991ca 100644 --- a/src/content/reference/react/useEffect.md +++ b/src/content/reference/react/useEffect.md @@ -44,7 +44,7 @@ function ChatRoom({ roomId }) { #### Parameters {/*parameters*/} -* `setup`: The function with your Effect's logic. Your setup function may also optionally return a *cleanup* function. When your component is first added to the DOM, React will run your setup function. After every re-render with changed dependencies, React will first run the cleanup function (if you provided it) with the old values, and then run your setup function with the new values. After your component is removed from the DOM, React will run your cleanup function one last time. +* `setup`: The function with your Effect's logic. Your setup function may also optionally return a *cleanup* function. When your component is added to the DOM, React will run your setup function. After every re-render with changed dependencies, React will first run the cleanup function (if you provided it) with the old values, and then run your setup function with the new values. After your component is removed from the DOM, React will run your cleanup function. * **optional** `dependencies`: The list of all reactive values referenced inside of the `setup` code. Reactive values include props, state, and all the variables and functions declared directly inside your component body. If your linter is [configured for React](/learn/editor-setup#linting), it will verify that every reactive value is correctly specified as a dependency. The list of dependencies must have a constant number of items and be written inline like `[dep1, dep2, dep3]`. React will compare each dependency with its previous value using the [`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) comparison. If you omit this argument, your Effect will re-run after every re-render of the component. [See the difference between passing an array of dependencies, an empty array, and no dependencies at all.](#examples-dependencies) diff --git a/src/content/reference/react/useInsertionEffect.md b/src/content/reference/react/useInsertionEffect.md index 5c92db2e6..175b4476f 100644 --- a/src/content/reference/react/useInsertionEffect.md +++ b/src/content/reference/react/useInsertionEffect.md @@ -44,7 +44,7 @@ function useCSS(rule) { #### Parameters {/*parameters*/} -* `setup`: The function with your Effect's logic. Your setup function may also optionally return a *cleanup* function. Before your component is first added to the DOM, React will run your setup function. After every re-render with changed dependencies, React will first run the cleanup function (if you provided it) with the old values, and then run your setup function with the new values. Before your component is removed from the DOM, React will run your cleanup function one last time. +* `setup`: The function with your Effect's logic. Your setup function may also optionally return a *cleanup* function. Before your component is added to the DOM, React will run your setup function. After every re-render with changed dependencies, React will first run the cleanup function (if you provided it) with the old values, and then run your setup function with the new values. Before your component is removed from the DOM, React will run your cleanup function. * **optional** `dependencies`: The list of all reactive values referenced inside of the `setup` code. Reactive values include props, state, and all the variables and functions declared directly inside your component body. If your linter is [configured for React](/learn/editor-setup#linting), it will verify that every reactive value is correctly specified as a dependency. The list of dependencies must have a constant number of items and be written inline like `[dep1, dep2, dep3]`. React will compare each dependency with its previous value using the [`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) comparison algorithm. If you don't specify the dependencies at all, your Effect will re-run after every re-render of the component. diff --git a/src/content/reference/react/useLayoutEffect.md b/src/content/reference/react/useLayoutEffect.md index fdbc50b3e..d30ebbd16 100644 --- a/src/content/reference/react/useLayoutEffect.md +++ b/src/content/reference/react/useLayoutEffect.md @@ -47,7 +47,7 @@ function Tooltip() { #### Parameters {/*parameters*/} -* `setup`: The function with your Effect's logic. Your setup function may also optionally return a *cleanup* function. Before your component is first added to the DOM, React will run your setup function. After every re-render with changed dependencies, React will first run the cleanup function (if you provided it) with the old values, and then run your setup function with the new values. Before your component is removed from the DOM, React will run your cleanup function one last time. +* `setup`: The function with your Effect's logic. Your setup function may also optionally return a *cleanup* function. Before your component is added to the DOM, React will run your setup function. After every re-render with changed dependencies, React will first run the cleanup function (if you provided it) with the old values, and then run your setup function with the new values. Before your component is removed from the DOM, React will run your cleanup function. * **optional** `dependencies`: The list of all reactive values referenced inside of the `setup` code. Reactive values include props, state, and all the variables and functions declared directly inside your component body. If your linter is [configured for React](/learn/editor-setup#linting), it will verify that every reactive value is correctly specified as a dependency. The list of dependencies must have a constant number of items and be written inline like `[dep1, dep2, dep3]`. React will compare each dependency with its previous value using the [`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) comparison. If you omit this argument, your Effect will re-run after every re-render of the component. @@ -737,7 +737,3 @@ However, if you're running into this problem, you have a few different options: - Alternatively, you can render a component with `useLayoutEffect` only after hydration. Keep a boolean `isMounted` state that's initialized to `false`, and set it to `true` inside a `useEffect` call. Your rendering logic can then be like `return isMounted ? : `. On the server and during the hydration, the user will see `FallbackContent` which should not call `useLayoutEffect`. Then React will replace it with `RealContent` which runs on the client only and can include `useLayoutEffect` calls. - If you synchronize your component with an external data store and rely on `useLayoutEffect` for different reasons than measuring layout, consider [`useSyncExternalStore`](/reference/react/useSyncExternalStore) instead which [supports server rendering.](/reference/react/useSyncExternalStore#adding-support-for-server-rendering) - - - - From b820dd5cca65f50231c5a841250da2ea0db9f952 Mon Sep 17 00:00:00 2001 From: jewhyena Date: Sat, 6 May 2023 15:36:32 +0300 Subject: [PATCH 129/233] Translate API reference / Hooks / useMemo --- src/content/reference/react/useMemo.md | 367 ++++++++++++------------- 1 file changed, 183 insertions(+), 184 deletions(-) diff --git a/src/content/reference/react/useMemo.md b/src/content/reference/react/useMemo.md index 543c11125..64ab4c7bc 100644 --- a/src/content/reference/react/useMemo.md +++ b/src/content/reference/react/useMemo.md @@ -4,7 +4,7 @@ title: useMemo -`useMemo` is a React Hook that lets you cache the result of a calculation between re-renders. +Хук `useMemo` позволяет кешировать результаты вычислений между ререндерами. ```js const cachedValue = useMemo(calculateValue, dependencies) @@ -16,11 +16,11 @@ const cachedValue = useMemo(calculateValue, dependencies) --- -## Reference {/*reference*/} +## Справочник {/*reference*/} ### `useMemo(calculateValue, dependencies)` {/*usememo*/} -Call `useMemo` at the top level of your component to cache a calculation between re-renders: +Чтобы закешировать результат вычислений между ререндерами, достаточно вызвать `useMemo` на верхнем уровне внутри компонента: ```js import { useMemo } from 'react'; @@ -34,39 +34,39 @@ function TodoList({ todos, tab }) { } ``` -[See more examples below.](#usage) +[Больше примеров.](#usage) -#### Parameters {/*parameters*/} +#### Параметры {/*parameters*/} -* `calculateValue`: The function calculating the value that you want to cache. It should be pure, should take no arguments, and should return a value of any type. React will call your function during the initial render. On next renders, React will return the same value again if the `dependencies` have not changed since the last render. Otherwise, it will call `calculateValue`, return its result, and store it so it can be reused later. +* `calculateValue`: Функция, возвращающая значение, которое нужно закешировать. Она должна быть чистой и не должна принимать никаких аргументов. React обязательно вызовет её при первом рендере, а при последующих будет возвращать готовое значение. В том случае если какое-то значение из массива зависимостей `dependencies` изменилось, React заново вызовет `calculateValue`, получит новое значение и сохранит его для будущего переиспользования. -* `dependencies`: The list of all reactive values referenced inside of the `calculateValue` code. Reactive values include props, state, and all the variables and functions declared directly inside your component body. If your linter is [configured for React](/learn/editor-setup#linting), it will verify that every reactive value is correctly specified as a dependency. The list of dependencies must have a constant number of items and be written inline like `[dep1, dep2, dep3]`. React will compare each dependency with its previous value using the [`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) comparison. +* `dependencies`: Массив всех реактивных значений, которые используются внутри функции `calculateValue`. Реактивные значения включают в себя пропсы, состояние и все переменные и функции, объявленные внутри компонента. Если вы настроили свой [линтер для работы с React](/learn/editor-setup#linting), он проверит, все ли реактивные компоненты были указаны как зависимости. Массив зависимостей должен иметь конечное число элементов и быть описан как `[dep1, dep2, dep3]`. React будет сравнивать каждую такую зависимость с её предыдущим значением при помощи [`Object.is`](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Object/is). -#### Returns {/*returns*/} +#### Возвращаемое значение {/*returns*/} -On the initial render, `useMemo` returns the result of calling `calculateValue` with no arguments. +При первом рендере `useMemo` возвращает результат вызова функции `calculateValue`. -During next renders, it will either return an already stored value from the last render (if the dependencies haven't changed), or call `calculateValue` again, and return the result that `calculateValue` has returned. +При всех последующих рендерах `useMemo` либо будет возвращать значение, сохранённое при предыдущем рендере (если ничто в массиве зависимостей не изменилось), либо заново вызовет функцию `calculateValue` и вернёт возвращаемое ею значение. -#### Caveats {/*caveats*/} +#### Предостережения {/*caveats*/} -* `useMemo` is a Hook, so you can only call it **at the top level of your component** or your own Hooks. You can't call it inside loops or conditions. If you need that, extract a new component and move the state into it. -* In Strict Mode, React will **call your calculation function twice** in order to [help you find accidental impurities.](#my-calculation-runs-twice-on-every-re-render) This is development-only behavior and does not affect production. If your calculation function is pure (as it should be), this should not affect your logic. The result from one of the calls will be ignored. -* React **will not throw away the cached value unless there is a specific reason to do that.** For example, in development, React throws away the cache when you edit the file of your component. Both in development and in production, React will throw away the cache if your component suspends during the initial mount. In the future, React may add more features that take advantage of throwing away the cache--for example, if React adds built-in support for virtualized lists in the future, it would make sense to throw away the cache for items that scroll out of the virtualized table viewport. This should be fine if you rely on `useMemo` solely as a performance optimization. Otherwise, a [state variable](/reference/react/useState#avoiding-recreating-the-initial-state) or a [ref](/reference/react/useRef#avoiding-recreating-the-ref-contents) may be more appropriate. +* Поскольку `useMemo` это хук, то вызывать его можно только **на верхнем уровне** внутри компонента или кастомного хука. Хуки нельзя вызывать внутри циклов или условий. Однако, если вам необходимо такое поведение, то можно извлечь новый компонент и переместить вызов хука в него. +* В строгом режиме React дважды вызовет передаваемую в `useMemo` функцию, чтобы проверить, [является ли она чистой](#my-calculation-runs-twice-on-every-re-render). Такое поведение существует только в режиме разработки и никак не проявляется в продакшене. Если эта функция чистая (какой она и должна быть), это никак не скажется на работе приложения. Результат одного из запусков будет просто проигнорирован. +* React **не отбрасывает закешированное значение, если на то нет веских причин**. Например, в режиме разработки React отбросит кеш, если файл компонента был изменён. В обоих режимах, разработки и продакшене, React отбросит кеш, если компонент [«задержится»](/reference/react/Suspense) во время первоначального монтирования. Помимо того, в дальнейшем в React могут быть добавлены новые возможности, которые смогут отбрасывать кеш. Например, если в будущем в React появится встроенная поддержка виртуализированных списков, будет иметь смысл отбрасывать кеш для тех элементов, которые выходят за область видимости. Полагаться на `useMemo` стоит только как на средство для оптимизации производительности. В противном случае, использование [состояния](/reference/react/useState#avoiding-recreating-the-initial-state) или [рефа](/reference/react/useRef#avoiding-recreating-the-ref-contents) может быть более подходящим вариантом. -Caching return values like this is also known as [*memoization*,](https://en.wikipedia.org/wiki/Memoization) which is why this Hook is called `useMemo`. +Подобное кеширование возвращаемых значений называют [*мемоизацией*](https://ru.wikipedia.org/wiki/%D0%9C%D0%B5%D0%BC%D0%BE%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F), поэтому данный хук был назван `useMemo`. --- -## Usage {/*usage*/} +## Использование {/*usage*/} -### Skipping expensive recalculations {/*skipping-expensive-recalculations*/} +### Пропуск ресурсоёмких вычислений {/*skipping-expensive-recalculations*/} -To cache a calculation between re-renders, wrap it in a `useMemo` call at the top level of your component: +Чтобы закешировать вычисления между ререндерами, достаточно обернуть их в `useMemo` на верхнем уровне внутри компонента: ```js [[3, 4, "visibleTodos"], [1, 4, "() => filterTodos(todos, tab)"], [2, 4, "[todos, tab]"]] import { useMemo } from 'react'; @@ -77,20 +77,20 @@ function TodoList({ todos, tab, theme }) { } ``` -You need to pass two things to `useMemo`: +`useMemo` ожидает два аргумента: -1. A calculation function that takes no arguments, like `() =>`, and returns what you wanted to calculate. -2. A list of dependencies including every value within your component that's used inside your calculation. +1. Вычислительную функцию, не принимающую никаких аргументов и возвращающую некоторое значение. +2. Массив зависимостей, включающий в себя все значения, находящиеся внутри компонента и использующиеся при вычислении. -On the initial render, the value you'll get from `useMemo` will be the result of calling your calculation. +При первом рендере значение, получаемое из `useMemo`, будет результатом вызова вычислительной функции. -On every subsequent render, React will compare the dependencies with the dependencies you passed during the last render. If none of the dependencies have changed (compared with [`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is)), `useMemo` will return the value you already calculated before. Otherwise, React will re-run your calculation and return the new value. +При всех последующих рендерах React будет сравнивать текущие зависимости с зависимостями из предыдущего рендера, используя [`Object.is`](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Object/is). Если никакие из зависимостей не изменились, `useMemo` вернёт вычисленное прежде значение. В противном случае, React заново запустит вычислительную функцию и вернёт новое значение. -In other words, `useMemo` caches a calculation result between re-renders until its dependencies change. +Иными словами, `useMemo` кеширует значение между ререндерами до тех пор, пока никакое значение из массива зависимостей не изменится. -**Let's walk through an example to see when this is useful.** +**Посмотрим на примере, когда это может быть полезно.** -By default, React will re-run the entire body of your component every time that it re-renders. For example, if this `TodoList` updates its state or receives new props from its parent, the `filterTodos` function will re-run: +По умолчанию при ререндере React заново перезапускает всё тело компонента. Например, если `TodoList` обновит своё состояние или получит новый пропс, функция `filterTodos` перезапустится: ```js {2} function TodoList({ todos, tab, theme }) { @@ -99,21 +99,21 @@ function TodoList({ todos, tab, theme }) { } ``` -Usually, this isn't a problem because most calculations are very fast. However, if you're filtering or transforming a large array, or doing some expensive computation, you might want to skip doing it again if data hasn't changed. If both `todos` and `tab` are the same as they were during the last render, wrapping the calculation in `useMemo` like earlier lets you reuse `visibleTodos` you've already calculated before. +Обычно это не такая большая проблема, поскольку большинство вычислений довольно быстрые. Однако если приходится фильтровать или преобразовывать большой массив данных, или совершать какие-то иные ресурсоёмкие вычисления, то имеет смысл их пропускать (если входные данные никак не изменились). Оборачивание вычислительной функции в `useMemo` позволит переиспользовать вычисленные ранее `visibleTodos` (если ни `todos`, ни `tab` никак не изменились с предыдущего рендера). -This type of caching is called *[memoization.](https://en.wikipedia.org/wiki/Memoization)* +Такой тип кеширования называют *[мемоизацией](https://ru.wikipedia.org/wiki/%D0%9C%D0%B5%D0%BC%D0%BE%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F)*. -**You should only rely on `useMemo` as a performance optimization.** If your code doesn't work without it, find the underlying problem and fix it first. Then you may add `useMemo` to improve performance. +**На хук `useMemo` стоит полагаться лишь как на средство для оптимизации производительности.** Если ваш код не работает без него, сперва стоит найти и исправить ошибку, и только затем думать об использовании `useMemo`. -#### How to tell if a calculation is expensive? {/*how-to-tell-if-a-calculation-is-expensive*/} +#### Как понять, ресурсоёмкие ли вычисления? {/*how-to-tell-if-a-calculation-is-expensive*/} -In general, unless you're creating or looping over thousands of objects, it's probably not expensive. If you want to get more confidence, you can add a console log to measure the time spent in a piece of code: +Если вы не создаёте или не проходите в цикле тысячи объектов, то вычисления, скорее всего, не ресурсоёмкие. Для измерения времени, затраченного на выполнение некоторого куска кода, можно воспользоваться следующими методами консоли: ```js {1,3} console.time('filter array'); @@ -121,59 +121,59 @@ const visibleTodos = filterTodos(todos, tab); console.timeEnd('filter array'); ``` -Perform the interaction you're measuring (for example, typing into the input). You will then see logs like `filter array: 0.15ms` in your console. If the overall logged time adds up to a significant amount (say, `1ms` or more), it might make sense to memoize that calculation. As an experiment, you can then wrap the calculation in `useMemo` to verify whether the total logged time has decreased for that interaction or not: +После выполнения функции `filterTodos` в консоли появятся логи типа `filter array: 0.15ms`. Если вычисление занимает довольно существенное количество времени (скажем, `1ms` или больше), то имеет смысл его мемоизировать. Для этого можно обернуть его в `useMemo` и проверить, уменьшилось ли общее время выполнения или нет: ```js console.time('filter array'); const visibleTodos = useMemo(() => { - return filterTodos(todos, tab); // Skipped if todos and tab haven't changed + return filterTodos(todos, tab); // Вычисление будет пропущено, если todos и tab не изменились }, [todos, tab]); console.timeEnd('filter array'); ``` -`useMemo` won't make the *first* render faster. It only helps you skip unnecessary work on updates. +`useMemo` не делает *первый* рендер быстрее. Он лишь позволяет пропускать ненужные вычисления при последующих ререндерах. -Keep in mind that your machine is probably faster than your users' so it's a good idea to test the performance with an artificial slowdown. For example, Chrome offers a [CPU Throttling](https://developer.chrome.com/blog/new-in-devtools-61/#throttling) option for this. +Стоит помнить, что ваша машина, скорее всего, мощнее, чем у ваших пользователей. Поэтому хорошей практикой будет измерять производительность, искусственно замедлив ваш компьютер. Например, в Chrome для этих целей существует [CPU Throttling](https://developer.chrome.com/blog/new-in-devtools-61/#throttling). -Also note that measuring performance in development will not give you the most accurate results. (For example, when [Strict Mode](/reference/react/StrictMode) is on, you will see each component render twice rather than once.) To get the most accurate timings, build your app for production and test it on a device like your users have. +Необходимо также учитывать, что измерение производительности в режиме разработки даёт не самые точные результаты. Например, при включённом [строгом режиме](/reference/react/StrictMode), React будет рендерить каждый компонент дважды. Чтобы получить наиболее точные результаты, тестирование нужно проводить в продакшен-режиме и на устройстве, подобном тому, которое используют ваши пользователи. -#### Should you add useMemo everywhere? {/*should-you-add-usememo-everywhere*/} +#### Везде ли стоит использовать useMemo? {/*should-you-add-usememo-everywhere*/} -If your app is like this site, and most interactions are coarse (like replacing a page or an entire section), memoization is usually unnecessary. On the other hand, if your app is more like a drawing editor, and most interactions are granular (like moving shapes), then you might find memoization very helpful. +В приложениях, подобных этому сайту, где большинство взаимодействий «грубые» (например, изменение страницы или целого раздела), мемоизация может быть излишня. С другой стороны, если ваше приложение больше похоже на графический редактор, где происходит много мелких взаимодействий (например, передвижение фигур), мемоизация может иметь смысл. -Optimizing with `useMemo` is only valuable in a few cases: +Прибегать к оптимизации при помощи `useMemo` стоит лишь в некоторых случаях: -- The calculation you're putting in `useMemo` is noticeably slow, and its dependencies rarely change. -- You pass it as a prop to a component wrapped in [`memo`.](/reference/react/memo) You want to skip re-rendering if the value hasn't changed. Memoization lets your component re-render only when dependencies aren't the same. -- The value you're passing is later used as a dependency of some Hook. For example, maybe another `useMemo` calculation value depends on it. Or maybe you are depending on this value from [`useEffect.`](/reference/react/useEffect) +- Если вычисление, помещаемое в `useMemo`, является ощутимо медленным и его зависимости редко изменяются. +- Если результат вычисления передаётся как проп дочернему компоненту, обёрнутому в [`memo`](/reference/react/memo). Мемоизация позволит пропускать его ререндеры, пока зависимости остаются прежними. +- Если вычисляемое значение в дальнейшем используется как зависимость другого хука. Например, если другой `useMemo` в своих вычислениях зависит от него. Или если это значение используется в [`useEffect`](/reference/react/useEffect). -There is no benefit to wrapping a calculation in `useMemo` in other cases. There is no significant harm to doing that either, so some teams choose to not think about individual cases, and memoize as much as possible. The downside of this approach is that code becomes less readable. Also, not all memoization is effective: a single value that's "always new" is enough to break memoization for an entire component. +В иных случаях особого смысла оборачивать вычисления в `useMemo` нет. Хотя в этом и нет ничего плохого: некоторые команды предпочитают не думать о каждом конкретном случае, а стараются мемоизировать как можно больше. Недостатком такого подхода может быть менее читаемый код. Кроме того, не любая мемоизация эффективна: одного значения, которое каждый раз новое, достаточно, чтобы сломать мемоизацию всего компонента. -**In practice, you can make a lot of memoization unnecessary by following a few principles:** +**Излишней мемоизации можно избежать, следуя таким принципам:** -1. When a component visually wraps other components, let it [accept JSX as children.](/learn/passing-props-to-a-component#passing-jsx-as-children) This way, when the wrapper component updates its own state, React knows that its children don't need to re-render. -1. Prefer local state and don't [lift state up](/learn/sharing-state-between-components) any further than necessary. For example, don't keep transient state like forms and whether an item is hovered at the top of your tree or in a global state library. -1. Keep your [rendering logic pure.](/learn/keeping-components-pure) If re-rendering a component causes a problem or produces some noticeable visual artifact, it's a bug in your component! Fix the bug instead of adding memoization. -1. Avoid [unnecessary Effects that update state.](/learn/you-might-not-need-an-effect) Most performance problems in React apps are caused by chains of updates originating from Effects that cause your components to render over and over. -1. Try to [remove unnecessary dependencies from your Effects.](/learn/removing-effect-dependencies) For example, instead of memoization, it's often simpler to move some object or a function inside an Effect or outside the component. +1. Когда один компонент визуально оборачивает другие компоненты, ему можно передать весь этот [JSX в виде дочерних компонентов](/learn/passing-props-to-a-component#passing-jsx-as-children). В таком случае, когда родительский компонент обновляет своё состояние, React будет знать, что дочерние компоненты не нуждаются в ререндере. +1. Храните состояние как можно локальнее и не [поднимайте его выше](/learn/sharing-state-between-components), чем это действительно необходимо. Не храните переходные состояния типа форм или проверок на hover в библиотеке для управления глобальным состоянием или на самом верху вашего дерева компонентов. +1. Храните ваши компоненты [чистыми](/learn/keeping-components-pure). Если ререндер компонента приводит к проблемам или производит какие-то визуальные артефакты – это баг! Исправьте его, а не прибегайте к мемоизации. +1. Избейгате лишних [Эффектов, которые обновляют состояние](/learn/you-might-not-need-an-effect). В React-приложениях большинство проблем с производительностью вызваны цепочками обновлений, которые создаются в Эффектах и вынуждают компоненты ререндериться снова и снова. +1. Постарайтесь [убрать лишние зависимости в Эффектах](/learn/removing-effect-dependencies). Иногда проще перенести функцию или объект внутрь функции Эффекта, или вынести их за пределы компонента, чем прибегать к мемоизации. -If a specific interaction still feels laggy, [use the React Developer Tools profiler](https://legacy.reactjs.org/blog/2018/09/10/introducing-the-react-profiler.html) to see which components would benefit the most from memoization, and add memoization where needed. These principles make your components easier to debug and understand, so it's good to follow them in any case. In the long term, we're researching [doing granular memoization automatically](https://www.youtube.com/watch?v=lGEMwh32soc) to solve this once and for all. +Если какие-то взаимодействия всё ещё ощущаются медленными, можно [воспользоваться профилировщиком из React DevTools](https://legacy.reactjs.org/blog/2018/09/10/introducing-the-react-profiler.html), чтобы посмотреть, каким компонентам больше всего нужна мемоизация, и затем добавить её там, где это необходимо. Эти принципы сделают ваши компоненты более простыми для отладки и понимания – поэтому ими не стоит пренебрегать. - + -#### Skipping recalculation with `useMemo` {/*skipping-recalculation-with-usememo*/} +#### Пропуск повторных вычислений при помощи `useMemo` {/*skipping-recalculation-with-usememo*/} -In this example, the `filterTodos` implementation is **artificially slowed down** so that you can see what happens when some JavaScript function you're calling during rendering is genuinely slow. Try switching the tabs and toggling the theme. +В данном примере функция `filterTodos` **искусственно замедлена**, чтобы показать, что случается в том случае, если вызываемая во время рендера функция действительно медленная. Попробуйте попереключаться между вкладками и попереключать тему. -Switching the tabs feels slow because it forces the slowed down `filterTodos` to re-execute. That's expected because the `tab` has changed, and so the entire calculation *needs* to re-run. (If you're curious why it runs twice, it's explained [here.](#my-calculation-runs-twice-on-every-re-render)) +Переключение вкладок ощущается таким медленным потому, что оно вынуждает перезапускаться замедленную функцию `filterTodos` каждый раз, когда изменяется значение `tab`. (Если интересно, почему она запускается дважды, объяснение можно найти [здесь](#my-calculation-runs-twice-on-every-re-render).) -Toggle the theme. **Thanks to `useMemo`, it's fast despite the artificial slowdown!** The slow `filterTodos` call was skipped because both `todos` and `tab` (which you pass as dependencies to `useMemo`) haven't changed since the last render. +**Однако изменение темы, благодаря `useMemo`, происходит быстро (несмотря на искусственное замедление).** Вызов функции `filterTodos` был пропущен потому, что ни `todos`, ни `tab`, указанные как зависимости в `useMemo`, никак не изменились с предыдущего рендера. @@ -190,13 +190,13 @@ export default function App() { return ( <>

            -

            Note: filterTodos is artificially slowed down!

            +

            Примечание: filterTodos искусственно замедлена!

              {visibleTodos.map(todo => (
            • @@ -260,10 +260,10 @@ export function createTodos() { } export function filterTodos(todos, tab) { - console.log('[ARTIFICIALLY SLOW] Filtering ' + todos.length + ' todos for "' + tab + '" tab.'); + console.log('[ЗАМЕДЛЕННО] Фильтрация ' + todos.length + ' todos для вкладки "' + tab + '"'); let startTime = performance.now(); while (performance.now() - startTime < 500) { - // Do nothing for 500 ms to emulate extremely slow code + // Ничего не делать 500 миллисекунд, чтобы сымитировать медленный код } return todos.filter(todo => { @@ -299,11 +299,11 @@ label { -#### Always recalculating a value {/*always-recalculating-a-value*/} +#### Повторное вычисление значения {/*always-recalculating-a-value*/} -In this example, the `filterTodos` implementation is also **artificially slowed down** so that you can see what happens when some JavaScript function you're calling during rendering is genuinely slow. Try switching the tabs and toggling the theme. +В данном примере функция `filterTodos` также замедлена, чтобы показать, что случается в том случае, если вызываемая во время рендера функция действительно медленная. Попробуйте попереключаться между вкладками и попереключать тему. -Unlike in the previous example, toggling the theme is also slow now! This is because **there is no `useMemo` call in this version,** so the artificially slowed down `filterTodos` gets called on every re-render. It is called even if only `theme` has changed. +Поскольку в этом примере отсутствует вызов `useMemo`, то искусственно замедленная функция `filterTodos` вызывается при каждом ререндере (даже в том случае, если изменилось только значение `theme`). @@ -320,13 +320,13 @@ export default function App() { return ( <>

                -

                Note: filterTodos is artificially slowed down!

                +

                Примечание: filterTodos искусственно замедлена!

                {visibleTodos.map(todo => (
              • {todo.completed ? @@ -386,10 +386,10 @@ export function createTodos() { } export function filterTodos(todos, tab) { - console.log('[ARTIFICIALLY SLOW] Filtering ' + todos.length + ' todos for "' + tab + '" tab.'); + console.log('[ЗАМЕДЛЕННО] Фильтрация ' + todos.length + ' todos для вкладки "' + tab + '"'); let startTime = performance.now(); while (performance.now() - startTime < 500) { - // Do nothing for 500 ms to emulate extremely slow code + // Ничего не делать 500 миллисекунд, чтобы сымитировать медленный код } return todos.filter(todo => { @@ -423,7 +423,7 @@ label { -However, here is the same code **with the artificial slowdown removed.** Does the lack of `useMemo` feel noticeable or not? +Ниже приведён код **без искусственного замедления**. Заметно ли отсутствие `useMemo`? @@ -440,13 +440,13 @@ export default function App() { return ( <>

                { if (tab === 'all') { @@ -538,9 +538,9 @@ label {
                -Quite often, code without memoization works fine. If your interactions are fast enough, you might not need memoization. +Часто код и без мемоизации работает хорошо. Нет необходимости использовать мемоизацию, если вычисления не ресурсоёмкие. -You can try increasing the number of todo items in `utils.js` and see how the behavior changes. This particular calculation wasn't very expensive to begin with, but if the number of todos grows significantly, most of the overhead will be in re-rendering rather than in the filtering. Keep reading below to see how you can optimize re-rendering with `useMemo`. +Можете попробовать увеличить количество todo в `utils.js` и посмотреть, как это скажется на скорости работы приложения. Изначально эти вычисления не очень ресурсоёмкое, однако если существенно увеличить количество todo, то дополнительная нагрузка будет вызвана скорее ререндером, чем фильтрацией. Ниже рассмотрим способы оптимизации ререндеров при помощи `useMemo`. @@ -548,9 +548,10 @@ You can try increasing the number of todo items in `utils.js` and see how the be --- -### Skipping re-rendering of components {/*skipping-re-rendering-of-components*/} +### Пропуск ререндеров дочерних компонентов {/*skipping-re-rendering-of-components*/} + +В некоторых случаях `useMemo` можно использовать для оптимизации ререндеров дочерних компонентов. Допустим, что `TodoList` передаёт как проп `visibleTodos` дочернему компоненту `List`: -In some cases, `useMemo` can also help you optimize performance of re-rendering child components. To illustrate this, let's say this `TodoList` component passes the `visibleTodos` as a prop to the child `List` component: ```js {5} export default function TodoList({ todos, tab, theme }) { @@ -563,9 +564,9 @@ export default function TodoList({ todos, tab, theme }) { } ``` -You've noticed that toggling the `theme` prop freezes the app for a moment, but if you remove `` from your JSX, it feels fast. This tells you that it's worth trying to optimize the `List` component. +В этом случае при изменении `theme` приложение будет на какое-то время подтормаживать. Однако если из разметки удалить ``, то всё будет работать быстро. -**By default, when a component re-renders, React re-renders all of its children recursively.** This is why, when `TodoList` re-renders with a different `theme`, the `List` component *also* re-renders. This is fine for components that don't require much calculation to re-render. But if you've verified that a re-render is slow, you can tell `List` to skip re-rendering when its props are the same as on last render by wrapping it in [`memo`:](/reference/react/memo) +**По умолчанию при ререндере некоторого компонента React рекурсивно ререндерит и всех его потомков.** По этой причине, когда `TodoList` ререндерится с другим значением `theme`, дочерний компонент `List` ререндерится *вместе* с ним. Это не страшно для компонентов, которые не производят никаких ресурсоёмких вычислений. Однако если ререндер заметно медленный (как с компонентом `List`), то имеет смысл обернуть его в [`memo`](/reference/react/memo). Это позволит избежать ререндеров, если пропсы с предыдущего рендера никак не изменились: ```js {3,5} import { memo } from 'react'; @@ -575,47 +576,46 @@ const List = memo(function List({ items }) { }); ``` -**With this change, `List` will skip re-rendering if all of its props are the *same* as on the last render.** This is where caching the calculation becomes important! Imagine that you calculated `visibleTodos` without `useMemo`: +**Теперь компонент `List` не будет ререндериться, если его пропсы с предыдущего рендера никак не изменились**. Однако представим, что `visibleTodos` вычисляется без `useMemo`: ```js {2-3,6-7} export default function TodoList({ todos, tab, theme }) { - // Every time the theme changes, this will be a different array... + // При каждом изменении theme функция filterTodos создаёт новый массив... const visibleTodos = filterTodos(todos, tab); return (
                - {/* ... so List's props will never be the same, and it will re-render every time */} + {/* ... поэтому компонент List всегда будет получать новые пропсы и ререндериться каждый раз */}
                ); } ``` -**In the above example, the `filterTodos` function always creates a *different* array,** similar to how the `{}` object literal always creates a new object. Normally, this wouldn't be a problem, but it means that `List` props will never be the same, and your [`memo`](/reference/react/memo) optimization won't work. This is where `useMemo` comes in handy: +Подобно тому как объектный литерал `{}` всегда создаёт новый объект, **функция `filterTodos` всегда создаёт новый массив**. Это значит, что компонент `List` всегда будет получать новые пропсы, и оптимизация при помощи [`memo`](/reference/react/memo) не работает. Здесь на помощь приходит `useMemo`: ```js {2-3,5,9-10} export default function TodoList({ todos, tab, theme }) { - // Tell React to cache your calculation between re-renders... + // Просим React закешировать вычисления между ререндерами... const visibleTodos = useMemo( () => filterTodos(todos, tab), - [todos, tab] // ...so as long as these dependencies don't change... + [todos, tab] // ...и пока эти зависимости не изменяются... ); return (
                - {/* ...List will receive the same props and can skip re-rendering */} + {/* ...List будет получать одинаковые пропсы и пропускать ререндеры */}
                ); } ``` - -**By wrapping the `visibleTodos` calculation in `useMemo`, you ensure that it has the *same* value between the re-renders** (until dependencies change). You don't *have to* wrap a calculation in `useMemo` unless you do it for some specific reason. In this example, the reason is that you pass it to a component wrapped in [`memo`,](/reference/react/memo) and this lets it skip re-rendering. There are a few other reasons to add `useMemo` which are described further on this page. +В примере выше `visibleTodos` всегда будет иметь *одно и то же* значение, пока массив зависимостей остаётся неизменным. Следует помнить, что нет необходимости использовать `useMemo` без веской на то причины. Однако в этом примере `visibleTodos` передаётся как пропс в компонент, обёрнутый в [`memo`](/reference/react/memo), что позволяет пропускать лишние ререндеры. -#### Memoizing individual JSX nodes {/*memoizing-individual-jsx-nodes*/} +#### Мемоизация отдельных JSX-узлов {/*memoizing-individual-jsx-nodes*/} -Instead of wrapping `List` in [`memo`](/reference/react/memo), you could wrap the `` JSX node itself in `useMemo`: +Вместо того чтобы оборачивать `List` в [`memo`](/reference/react/memo), можно обернуть сам JSX-узел `` в `useMemo`: ```js {3,6} export default function TodoList({ todos, tab, theme }) { @@ -629,25 +629,25 @@ export default function TodoList({ todos, tab, theme }) { } ``` -The behavior would be the same. If the `visibleTodos` haven't changed, `List` won't be re-rendered. +Поведение будет таким же. Компонент `List` не будет ререндериться, пока значение `visibleTodos` остаётся неизменным. -A JSX node like `` is an object like `{ type: List, props: { items: visibleTodos } }`. Creating this object is very cheap, but React doesn't know whether its contents is the same as last time or not. This is why by default, React will re-render the `List` component. +JSX-узел `` является простым объектом типа `{ type: List, props: { items: visibleTodos } }`. Создание такого объекта – довольно дешёвая операция, однако React не знает, осталось ли его содержимое прежним или нет. Поэтому по умолчанию React всегда будет ререндерить компонент `List`. -However, if React sees the same exact JSX as during the previous render, it won't try to re-render your component. This is because JSX nodes are [immutable.](https://en.wikipedia.org/wiki/Immutable_object) A JSX node object could not have changed over time, so React knows it's safe to skip a re-render. However, for this to work, the node has to *actually be the same object*, not merely look the same in code. This is what `useMemo` does in this example. +При этом, если React видит тот же JSX, который был при предыдущем рендере, он не будет ререндерить компонент. Так происходит потому, что JSX-узлы являются [неизменяемыми объектами](https://ru.wikipedia.org/wiki/%D0%9D%D0%B5%D0%B8%D0%B7%D0%BC%D0%B5%D0%BD%D1%8F%D0%B5%D0%BC%D1%8B%D0%B9_%D0%BE%D0%B1%D1%8A%D0%B5%D0%BA%D1%82). Такие объекты не могут быть изменены с течением времени, поэтому React знает, что пропустить ререндер – безопасно. Однако чтобы это работало, узел должен быть *буквально тем же объектом*, а не только *выглядеть* таким же в коде. Это именно то, что делает `useMemo` в данном примере. -Manually wrapping JSX nodes into `useMemo` is not convenient. For example, you can't do this conditionally. This is usually why you would wrap components with [`memo`](/reference/react/memo) instead of wrapping JSX nodes. +Оборачивать JSX-узлы в `useMemo` не всегда удобно. Например, это нельзя делать по условию. По этой причине компоненты чаще оборачивают в [`memo`](/reference/react/memo). - + -#### Skipping re-rendering with `useMemo` and `memo` {/*skipping-re-rendering-with-usememo-and-memo*/} +#### Пропуск ререндеров при помощи `useMemo` и `memo` {/*skipping-re-rendering-with-usememo-and-memo*/} -In this example, the `List` component is **artificially slowed down** so that you can see what happens when a React component you're rendering is genuinely slow. Try switching the tabs and toggling the theme. +В данном примере компонент `List` искусственно замедлен, чтобы показать, что случается в том случае, если React-компонент действительно медленный. Попробуйте попереключаться между вкладками и попереключать тему. -Switching the tabs feels slow because it forces the slowed down `List` to re-render. That's expected because the `tab` has changed, and so you need to reflect the user's new choice on the screen. +Переключение между вкладками ощущается таким медленным, потому что оно вынуждает замедленный компонент `List` ререндериться. Такое поведение ожидаемо, поскольку проп `tab` изменился, и новые данные необходимо отобразить на экране. -Next, try toggling the theme. **Thanks to `useMemo` together with [`memo`](/reference/react/memo), it’s fast despite the artificial slowdown!** The `List` skipped re-rendering because the `visibleItems` array has not changed since the last render. The `visibleItems` array has not changed because both `todos` and `tab` (which you pass as dependencies to `useMemo`) haven't changed since the last render. +Однако изменение темы (благодаря `useMemo` в связке с [`memo`](/reference/react/memo)) происходит быстро, несмотря на искусственное замедление. Поскольку ни `todos`, ни `tab`, указанные как зависимости в `useMemo`, не изменились с предыдущего рендера, то массив `visibleTodos` остался прежним, и компонент `List` пропустил ререндер. @@ -664,13 +664,13 @@ export default function App() { return ( <>

                -

                Note: List is artificially slowed down!

                +

                Примечание: компонент List искусственно замедлен!

          7. ); @@ -715,10 +715,10 @@ export default function TodoList({ todos, theme, tab }) { import { memo } from 'react'; const List = memo(function List({ items }) { - console.log('[ARTIFICIALLY SLOW] Rendering with ' + items.length + ' items'); + console.log('[ЗАМЕДЛЕННО] Рендер компонента с ' + items.length + ' элементами'); let startTime = performance.now(); while (performance.now() - startTime < 500) { - // Do nothing for 500 ms to emulate extremely slow code + // Ничего не делать 500 миллисекунд, чтобы сымитировать медленный код } return ( @@ -785,11 +785,11 @@ label { -#### Always re-rendering a component {/*always-re-rendering-a-component*/} +#### Повторный ререндер компонента {/*always-re-rendering-a-component*/} -In this example, the `List` implementation is also **artificially slowed down** so that you can see what happens when some React component you're rendering is genuinely slow. Try switching the tabs and toggling the theme. +В данном примере компонент `List` также искусственно замедлен, чтобы показать, что случается в том случае, если React-компонент действительно медленный. Попробуйте попереключаться между вкладками и попереключать тему. -Unlike in the previous example, toggling the theme is also slow now! This is because **there is no `useMemo` call in this version,** so the `visibleTodos` is always a different array, and the slowed down `List` component can't skip re-rendering. +В отличие от предыдущего примера, здесь отсутствует `useMemo`. По этой причине `visibleTodos` всегда будет новым массивом, и компонент `List` не сможет пропустить ререндер. @@ -806,13 +806,13 @@ export default function App() { return ( <>

            -

            Note: List is artificially slowed down!

            +

            Примечание: компонент List искусственно замедлен!

            ); @@ -853,10 +853,10 @@ export default function TodoList({ todos, theme, tab }) { import { memo } from 'react'; const List = memo(function List({ items }) { - console.log('[ARTIFICIALLY SLOW] Rendering with ' + items.length + ' items'); + console.log('[ЗАМЕДЛЕННО] Рендер компонента с ' + items.length + ' элементами'); let startTime = performance.now(); while (performance.now() - startTime < 500) { - // Do nothing for 500 ms to emulate extremely slow code + // Ничего не делать 500 миллисекунд, чтобы сымитировать медленный код } return ( @@ -921,7 +921,7 @@ label { -However, here is the same code **with the artificial slowdown removed.** Does the lack of `useMemo` feel noticeable or not? +Ниже приведён код **без искусственного замедления**. Заметно ли отсутствие `memo` и `useMemo`? @@ -938,13 +938,13 @@ export default function App() { return ( <>

            -Quite often, code without memoization works fine. If your interactions are fast enough, you don't need memoization. +Часто код и без мемоизации работает хорошо. Нет необходимости использовать мемоизацию, если вычисления не ресурсоёмкие. -Keep in mind that you need to run React in production mode, disable [React Developer Tools](/learn/react-developer-tools), and use devices similar to the ones your app's users have in order to get a realistic sense of what's actually slowing down your app. +Чтобы получить наиболее реалистичные данные относительно того, что может замедлять ваше приложение, React стоит запускать в продакшен-режиме, с отключёнными [React DevTools](/learn/react-developer-tools) и на устройстве, подобном тому, которое используют ваши пользователи. @@ -1056,9 +1056,9 @@ Keep in mind that you need to run React in production mode, disable [React Devel --- -### Memoizing a dependency of another Hook {/*memoizing-a-dependency-of-another-hook*/} +### Мемоизация зависимостей других хуков {/*memoizing-a-dependency-of-another-hook*/} -Suppose you have a calculation that depends on an object created directly in the component body: +Предположим, что у нас есть вычисления, зависящие от объекта, создаваемого внутри компонента: ```js {2} function Dropdown({ allItems, text }) { @@ -1066,44 +1066,44 @@ function Dropdown({ allItems, text }) { const visibleItems = useMemo(() => { return searchItems(allItems, searchOptions); - }, [allItems, searchOptions]); // 🚩 Caution: Dependency on an object created in the component body + }, [allItems, searchOptions]); // 🚩 Зависимость от объекта, создаваемого внутри компонента // ... ``` -Depending on an object like this defeats the point of memoization. When a component re-renders, all of the code directly inside the component body runs again. **The lines of code creating the `searchOptions` object will also run on every re-render.** Since `searchOptions` is a dependency of your `useMemo` call, and it's different every time, React knows the dependencies are different, and recalculate `searchItems` every time. +Подобная зависимость сводит на нет все преимущества мемоизации. При ререндере компонента весь его внутренний код перезапускается, **включая создание объекта `searchOptions`**. И поскольку этот объект является зависимостью `useMemo`, React каждый раз будет заново вычислять значение `visibleItems`. -To fix this, you could memoize the `searchOptions` object *itself* before passing it as a dependency: +Чтобы исправить такое поведение, можно мемоизировать сам объект `searchOptions` перед тем как передавать его в виде зависимости: ```js {2-4} function Dropdown({ allItems, text }) { const searchOptions = useMemo(() => { return { matchMode: 'whole-word', text }; - }, [text]); // ✅ Only changes when text changes + }, [text]); // ✅ Вызывается только при изменении text const visibleItems = useMemo(() => { return searchItems(allItems, searchOptions); - }, [allItems, searchOptions]); // ✅ Only changes when allItems or searchOptions changes + }, [allItems, searchOptions]); // ✅ Вызывается только при изменении allItems или searchOptions // ... ``` -In the example above, if the `text` did not change, the `searchOptions` object also won't change. However, an even better fix is to move the `searchOptions` object declaration *inside* of the `useMemo` calculation function: +В примере выше `searchOptions` будет изменяться только при изменении `text`. При этом можно сделать ещё лучше – переместить объект `searchOptions` *внутрь* вычислительной функции `useMemo`: ```js {3} function Dropdown({ allItems, text }) { const visibleItems = useMemo(() => { const searchOptions = { matchMode: 'whole-word', text }; return searchItems(allItems, searchOptions); - }, [allItems, text]); // ✅ Only changes when allItems or text changes + }, [allItems, text]); // ✅ Вызывается только при изменении allItems или text // ... ``` -Now your calculation depends on `text` directly (which is a string and can't "accidentally" become different). +Теперь вычисления зависят напрямую от значения `text`, которое является строчным и не может измениться «незаметно». --- -### Memoizing a function {/*memoizing-a-function*/} +### Мемоизация функций {/*memoizing-a-function*/} -Suppose the `Form` component is wrapped in [`memo`.](/reference/react/memo) You want to pass a function to it as a prop: +Предположим, что компонент `Form` обёрнут в [`memo`](/reference/react/memo) и получает как проп функцию: ```js {2-7} export default function ProductPage({ productId, referrer }) { @@ -1118,9 +1118,9 @@ export default function ProductPage({ productId, referrer }) { } ``` -Just as `{}` creates a different object, function declarations like `function() {}` and expressions like `() => {}` produce a *different* function on every re-render. By itself, creating a new function is not a problem. This is not something to avoid! However, if the `Form` component is memoized, presumably you want to skip re-rendering it when no props have changed. A prop that is *always* different would defeat the point of memoization. +Подобно тому как объектный литерал `{}` создаёт новый объект, определение функции через `function() {}` или `() => {}` создаёт новую функцию при каждом ререндере. Само по себе создание функций не является проблемой (и этого, конечно, не стоит избегать). Однако поскольку компонент `Form` мемоизирован, стоит подумать о пропуске лишних ререндеров, если его пропсы остаются неизменными. -To memoize a function with `useMemo`, your calculation function would have to return another function: +Чтобы мемоизировать функцию, можно вернуть её из вычислительной функции `useMemo`: ```js {2-3,8-9} export default function Page({ productId, referrer }) { @@ -1137,7 +1137,7 @@ export default function Page({ productId, referrer }) { } ``` -This looks clunky! **Memoizing functions is common enough that React has a built-in Hook specifically for that. Wrap your functions into [`useCallback`](/reference/react/useCallback) instead of `useMemo`** to avoid having to write an extra nested function: +**Поскольку мемоизация функций – довольно распространённая задача, в React есть встроенный хук специально для этих целей**. Вместо `useMemo` можно обернуть функцию в [`useCallback`](/reference/react/useCallback) и избежать написания дополнительной вложенной функции: ```js {2,7} export default function Page({ productId, referrer }) { @@ -1152,88 +1152,87 @@ export default function Page({ productId, referrer }) { } ``` -The two examples above are completely equivalent. The only benefit to `useCallback` is that it lets you avoid writing an extra nested function inside. It doesn't do anything else. [Read more about `useCallback`.](/reference/react/useCallback) +Два примера выше абсолютно идентичны. Единственное преимущество использования хука `useCallback` в том, что он позволяет избежать написания дополнительной вложенной функции. Ознакомиться подробнее с хуком `useCallback` можно [здесь](/reference/react/useCallback). --- -## Troubleshooting {/*troubleshooting*/} +## Диагностика неполадок {/*troubleshooting*/} -### My calculation runs twice on every re-render {/*my-calculation-runs-twice-on-every-re-render*/} +### Вычисления запускаются дважды при каждом ререндере {/*my-calculation-runs-twice-on-every-re-render*/} -In [Strict Mode](/reference/react/StrictMode), React will call some of your functions twice instead of once: +В [строгом режиме](/reference/react/StrictMode) React запускает некоторые функции дважды: ```js {2,5,6} function TodoList({ todos, tab }) { - // This component function will run twice for every render. + // Функция компонента будет запускаться дважды при каждом рендере const visibleTodos = useMemo(() => { - // This calculation will run twice if any of the dependencies change. + // Эти вычисления также запустятся дважды, если любая из зависимостей изменится return filterTodos(todos, tab); }, [todos, tab]); // ... ``` -This is expected and shouldn't break your code. +Такое поведение ожидаемо, и не должно сломать ваш код. -This **development-only** behavior helps you [keep components pure.](/learn/keeping-components-pure) React uses the result of one of the calls, and ignores the result of the other call. As long as your component and calculation functions are pure, this shouldn't affect your logic. However, if they are accidentally impure, this helps you notice and fix the mistake. +Оно существует только в режиме разработки и помогает разработчику [хранить компоненты чистыми](/learn/keeping-components-pure). React будет использовать данные лишь одного из вызовов и проигнорирует все остальные. Это не должно негативно сказаться на работе приложения, если компонент и вычислительная функция чистые. Однако если в коде существуют функции с [побочными эффектами](https://ru.wikipedia.org/wiki/%D0%9F%D0%BE%D0%B1%D0%BE%D1%87%D0%BD%D1%8B%D0%B9_%D1%8D%D1%84%D1%84%D0%B5%D0%BA%D1%82_(%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5)), это поможет их обнаружить. -For example, this impure calculation function mutates an array you received as a prop: +Например, в коде ниже вычислительная функция мутирует массив, полученный из пропсов: ```js {2-3} const visibleTodos = useMemo(() => { - // 🚩 Mistake: mutating a prop + // 🚩 Внимание: мутация пропса todos.push({ id: 'last', text: 'Go for a walk!' }); const filtered = filterTodos(todos, tab); return filtered; }, [todos, tab]); ``` -React calls your function twice, so you'd notice the todo is added twice. Your calculation shouldn't change any existing objects, but it's okay to change any *new* objects you created during the calculation. For example, if the `filterTodos` function always returns a *different* array, you can mutate *that* array instead: +Благодаря тому что React вызовет эту функцию дважды, разработчик заметит, что один и тот же todo был добавлен два раза. Изменять новые объекты, созданные внутри вычислений – нормально, но никакие существующие объекты изменяться *не должны*. Так, например, если функция `filterTodos` всегда возвращает *новый* массив, то мутировать его перед возвращением можно: ```js {3,4} const visibleTodos = useMemo(() => { const filtered = filterTodos(todos, tab); - // ✅ Correct: mutating an object you created during the calculation + // ✅ Мутация объекта, созданного в процессе вычислений filtered.push({ id: 'last', text: 'Go for a walk!' }); return filtered; }, [todos, tab]); ``` -Read [keeping components pure](/learn/keeping-components-pure) to learn more about purity. +Больше о сохранении компонентов чистым можно прочитать [здесь](/learn/keeping-components-pure). -Also, check out the guides on [updating objects](/learn/updating-objects-in-state) and [updating arrays](/learn/updating-arrays-in-state) without mutation. +Помимо того, можно ознакомиться с руководствами по обновлению [объектов](/learn/updating-objects-in-state) и [массивов](/learn/updating-arrays-in-state) без мутаций. --- -### My `useMemo` call is supposed to return an object, but returns undefined {/*my-usememo-call-is-supposed-to-return-an-object-but-returns-undefined*/} - -This code doesn't work: +### `useMemo` должен возвращать объект, а возвращает undefined {/*my-usememo-call-is-supposed-to-return-an-object-but-returns-undefined*/} +Этот код не работает: ```js {1-2,5} - // 🔴 You can't return an object from an arrow function with () => { + // 🔴 Такой записью вернуть объект из стрелочной функции нельзя: const searchOptions = useMemo(() => { matchMode: 'whole-word', text: text }, [text]); ``` -In JavaScript, `() => {` starts the arrow function body, so the `{` brace is not a part of your object. This is why it doesn't return an object, and leads to mistakes. You could fix it by adding parentheses like `({` and `})`: +В языке JavaScript запись `() => {` открывает тело стрелочной функции и скобка `{` не является частью объекта. По этой причине функция не возвращает объект, что и приводит к ошибке. Это можно исправить, добавив круглые скобки: `({` и `})`: ```js {1-2,5} - // This works, but is easy for someone to break again + // Этот код работает, однако его легко заново сломать const searchOptions = useMemo(() => ({ matchMode: 'whole-word', text: text }), [text]); ``` -However, this is still confusing and too easy for someone to break by removing the parentheses. +Подобная запись может сбивать с толку, и этот код можно заново сломать, случайно удалив скобки. -To avoid this mistake, write a `return` statement explicitly: +Чтобы этого избежать, можно явно написать `return`: ```js {1-3,6-7} - // ✅ This works and is explicit + // ✅ Этот код работает и при этом он описан явно const searchOptions = useMemo(() => { return { matchMode: 'whole-word', @@ -1244,57 +1243,57 @@ To avoid this mistake, write a `return` statement explicitly: --- -### Every time my component renders, the calculation in `useMemo` re-runs {/*every-time-my-component-renders-the-calculation-in-usememo-re-runs*/} +### Вычисления в `useMemo` запускаются при каждом рендере {/*every-time-my-component-renders-the-calculation-in-usememo-re-runs*/} -Make sure you've specified the dependency array as a second argument! +Убедитесь, что в `useMemo` был передан массив зависимостей. -If you forget the dependency array, `useMemo` will re-run the calculation every time: +Если не указан массив зависимостей, то `useMemo` будет перезапускаться каждый раз: ```js {2-3} function TodoList({ todos, tab }) { - // 🔴 Recalculates every time: no dependency array + // 🔴 Нет массива зависимостей – перезапускается каждый раз const visibleTodos = useMemo(() => filterTodos(todos, tab)); // ... ``` -This is the corrected version passing the dependency array as a second argument: +Исправленная версия с массивом зависимостей выглядит так: ```js {2-3} function TodoList({ todos, tab }) { - // ✅ Does not recalculate unnecessarily + // ✅ Не перезапускается без надобности const visibleTodos = useMemo(() => filterTodos(todos, tab), [todos, tab]); // ... ``` -If this doesn't help, then the problem is that at least one of your dependencies is different from the previous render. You can debug this problem by manually logging your dependencies to the console: +Если это не помогло, то проблема может быть в том, что какая-то зависимось получает новое значение при каждом рендере. Эту проблему можно отладить, выведя массив зависимостей в консоль: ```js const visibleTodos = useMemo(() => filterTodos(todos, tab), [todos, tab]); console.log([todos, tab]); ``` -You can then right-click on the arrays from different re-renders in the console and select "Store as a global variable" for both of them. Assuming the first one got saved as `temp1` and the second one got saved as `temp2`, you can then use the browser console to check whether each dependency in both arrays is the same: +Затем в консоли можно нажать по массивам правой кнопкой мыши и для обоих выбрать опцию «Сохранить как глобальную переменную». Первый сохраним как `temp1`, а второй – как `temp2`. Здесь же можно проверить, все ли зависимости в массивах одинаковые: ```js -Object.is(temp1[0], temp2[0]); // Is the first dependency the same between the arrays? -Object.is(temp1[1], temp2[1]); // Is the second dependency the same between the arrays? -Object.is(temp1[2], temp2[2]); // ... and so on for every dependency ... +Object.is(temp1[0], temp2[0]); // Одинаковы ли первые значения? +Object.is(temp1[1], temp2[1]); // Одинаковы ли вторые значения? +Object.is(temp1[2], temp2[2]); // ... и так для всех зависимостей ... ``` -When you find which dependency breaks memoization, either find a way to remove it, or [memoize it as well.](#memoizing-a-dependency-of-another-hook) +После того как необходимая зависимость была найдена, можно попробовать убрать её или попытаться [мемоизировать](#memoizing-a-dependency-of-another-hook). --- -### I need to call `useMemo` for each list item in a loop, but it's not allowed {/*i-need-to-call-usememo-for-each-list-item-in-a-loop-but-its-not-allowed*/} +### Нужно вызвать `useMemo` для каждого элемента в цикле, но это запрещено {/*i-need-to-call-usememo-for-each-list-item-in-a-loop-but-its-not-allowed*/} -Suppose the `Chart` component is wrapped in [`memo`](/reference/react/memo). You want to skip re-rendering every `Chart` in the list when the `ReportList` component re-renders. However, you can't call `useMemo` in a loop: +Предположим, что компонент `Chart` обёрнут в [`memo`](/reference/react/memo). Необходимо пропустить ререндеры для каждого из них, если родительский компонент `ReportList` ререндерится. Однако вызывать `useMemo` в циклах запрещено: ```js {5-11} function ReportList({ items }) { return (
            {items.map(item => { - // 🔴 You can't call useMemo in a loop like this: + // 🔴 Нельзя вызвать `useMemo` внутри цикла const data = useMemo(() => calculateReport(item), [item]); return (
            @@ -1307,7 +1306,7 @@ function ReportList({ items }) { } ``` -Instead, extract a component for each item and memoize data for individual items: +Вместо этого можно извлечь новый компонент и мемоизировать данные внутри него: ```js {5,12-18} function ReportList({ items }) { @@ -1321,7 +1320,7 @@ function ReportList({ items }) { } function Report({ item }) { - // ✅ Call useMemo at the top level: + // ✅ Вызов useMemo на верхнем уровне компонента const data = useMemo(() => calculateReport(item), [item]); return (
            @@ -1331,7 +1330,7 @@ function Report({ item }) { } ``` -Alternatively, you could remove `useMemo` and instead wrap `Report` itself in [`memo`.](/reference/react/memo) If the `item` prop does not change, `Report` will skip re-rendering, so `Chart` will skip re-rendering too: +В качестве альтернативного варианта можно убрать `useMemo`, и вместо него обернуть сам `Report` в [`memo`](/reference/react/memo). В этом случае если проп `item` не изменится, то `Report` пропустит ререндер вместе со своим дочерним компонентом `Chart`: ```js {5,6,12} function ReportList({ items }) { From efa42a7411c3477c80075e42dcaf3a2a27959d74 Mon Sep 17 00:00:00 2001 From: Jana Korichneva Date: Mon, 1 May 2023 13:58:42 +0400 Subject: [PATCH 130/233] feat: translation of strict mode --- src/content/reference/react/StrictMode.md | 140 +++++++++++----------- 1 file changed, 70 insertions(+), 70 deletions(-) diff --git a/src/content/reference/react/StrictMode.md b/src/content/reference/react/StrictMode.md index b7ca2227c..320d190a3 100644 --- a/src/content/reference/react/StrictMode.md +++ b/src/content/reference/react/StrictMode.md @@ -5,7 +5,7 @@ title: -`` lets you find common bugs in your components early during development. +`` позволяет находить распространенные баги в компонентах на ранней стадии разработки. ```js @@ -20,11 +20,11 @@ title: --- -## Reference {/*reference*/} +## Справочник {/*reference*/} ### `` {/*strictmode*/} -Use `StrictMode` to enable additional development behaviors and warnings for the component tree inside: +Используйте `StrictMode`, чтобы включить дополнительные проверки и предупреждения для потомков дерева компонентов: ```js import { StrictMode } from 'react'; @@ -38,32 +38,32 @@ root.render( ); ``` -[See more examples below.](#usage) +[Больше примеров использования.](#usage) -Strict Mode enables the following development-only behaviors: +Строгий режим активирует следующее поведение в режиме разработки: -- Your components will [re-render an extra time](#fixing-bugs-found-by-double-rendering-in-development) to find bugs caused by impure rendering. -- Your components will [re-run Effects an extra time](#fixing-bugs-found-by-re-running-effects-in-development) to find bugs caused by missing Effect cleanup. -- Your components will [be checked for usage of deprecated APIs.](#fixing-deprecation-warnings-enabled-by-strict-mode) +- Ваши компоненты будут [рендерится повторно](#fixing-bugs-found-by-double-rendering-in-development) чтобы можно было найти баги, вызванные нечистым рендерингом. +- Ваши компоненты будут [повторно запускать эффекты](#fixing-bugs-found-by-re-running-effects-in-development), чтобы можно было найти баги возникающие из-за отсутствия сбрасывающей функции в эффекте. +- Ваши компоненты будут [проверяться на использование устаревших API.](#fixing-deprecation-warnings-enabled-by-strict-mode) -#### Props {/*props*/} +#### Пропсы {/*props*/} -`StrictMode` accepts no props. +`StrictMode` не принимает никаких пропсов. -#### Caveats {/*caveats*/} +#### Предостережения {/*caveats*/} -* There is no way to opt out of Strict Mode inside a tree wrapped in ``. This gives you confidence that all components inside `` are checked. If two teams working on a product disagree whether they find the checks valuable, they need to either reach consensus or move `` down in the tree. +* Если ваше дерево обернуто в ``, то сделать исключение из строгого режима невозможно. Это дает вам уверенность, что все компоненты внутри `` будут проверены. Если две команды работают над одним продуктом и не могут прийти к соглашению, нужны ли им эти проверки, то нужно или достичь компромисса, или переместить `` ниже по дереву. --- -## Usage {/*usage*/} +## Применение {/*usage*/} -### Enabling Strict Mode for entire app {/*enabling-strict-mode-for-entire-app*/} +### Как включить строгий режим для всего приложения {/*enabling-strict-mode-for-entire-app*/} -Strict Mode enables extra development-only checks for the entire component tree inside the `` component. These checks help you find common bugs in your components early in the development process. +Strict Mode включает дополнительные проверки для всего дерева компонентов внутри `` в режиме разработки. Эти проверки позволяют находить распространенные баги в компонентах на ранней стадии разработки. -To enable Strict Mode for your entire app, wrap your root component with `` when you render it: +Чтобы включить Strict Mode для всего приложения, оберните ваш корень вашего приложения в `` при рендеринге: ```js {6,8} import { StrictMode } from 'react'; @@ -77,27 +77,27 @@ root.render( ); ``` -We recommend wrapping your entire app in Strict Mode, especially for newly created apps. If you use a framework that calls [`createRoot`](/reference/react-dom/client/createRoot) for you, check its documentation for how to enable Strict Mode. +Мы рекомендуем целиком оборачивать ваше приложение (особенно, если оно новое) в строгий режим. Если вы используете фреймворк, который вызывает за вас [`createRoot`](/reference/react-dom/client/createRoot), посмотрите как включить строгий режим в его документации. -Although the Strict Mode checks **only run in development,** they help you find bugs that already exist in your code but can be tricky to reliably reproduce in production. Strict Mode lets you fix bugs before your users report them. +Несмотря на то, что проверки строгого режима **выполняются только в режиме разработки,** они помогают вам находить ошибки, которые уже существуют в вашем коде, и их может быть сложно стабильно воспроизвести в продакшене. Строгий режим позволяет исправлять такие ошибки до того, как ваши пользователи сообщат о них. -Strict Mode enables the following checks in development: +Строгий режим включает следующие дополнительные проверки в режиме разработки: -- Your components will [re-render an extra time](#fixing-bugs-found-by-double-rendering-in-development) to find bugs caused by impure rendering. -- Your components will [re-run Effects an extra time](#fixing-bugs-found-by-re-running-effects-in-development) to find bugs caused by missing Effect cleanup. -- Your components will [be checked for usage of deprecated APIs.](#fixing-deprecation-warnings-enabled-by-strict-mode) +- Ваши компоненты будут [рендерится повторно](#fixing-bugs-found-by-double-rendering-in-development) чтобы можно было найти баги, вызванные нечистым рендерингом. +- Ваши компоненты будут [повторно запускать эффекты](#fixing-bugs-found-by-re-running-effects-in-development) чтобы можно было найти баги возникающие из-за отсутствия сбрасывающей функции в эффекте. +- Ваши компоненты будут [проверяться на использование устаревших APIs.](#fixing-deprecation-warnings-enabled-by-strict-mode) -**All of these checks are development-only and do not impact the production build.** +**Все эти проверки работают только в режиме разработки и не оказывают никакого эффекта в продакшен-сборке.** --- -### Enabling strict mode for a part of the app {/*enabling-strict-mode-for-a-part-of-the-app*/} +### Как включить строгий режим для части приложения {/*enabling-strict-mode-for-a-part-of-the-app*/} -You can also enable Strict Mode for any part of your application: +Строгий режим может быть включён для любой части вашего приложения: ```js {7,12} import { StrictMode } from 'react'; @@ -118,25 +118,25 @@ function App() { } ``` -In this example, Strict Mode checks will not run against the `Header` and `Footer` components. However, they will run on `Sidebar` and `Content`, as well as all of the components inside them, no matter how deep. +В этом примере проверки строгого режима не будут выполняться для компонентов `Header` и `Footer`. Однако, они будут выполняться для `Sidebar` и `Content`, так же как и для всех компонентов внутри них, независимо от глубины вложенности. --- -### Fixing bugs found by double rendering in development {/*fixing-bugs-found-by-double-rendering-in-development*/} +### Исправление багов, найденных повторным рендерингом в режиме разработки {/*fixing-bugs-found-by-double-rendering-in-development*/} -[React assumes that every component you write is a pure function.](/learn/keeping-components-pure) This means that React components you write must always return the same JSX given the same inputs (props, state, and context). +[React предполагает, что каждый компонент является чистой функцией.](/learn/keeping-components-pure) Это значит, что React-компоненты, которые вы пишете, должны всегда возвращать одинаковый JSX при тех же входных данных (пропсах, состоянии и контексте). -Components breaking this rule behave unpredictably and cause bugs. To help you find accidentally impure code, Strict Mode calls some of your functions (only the ones that should be pure) **twice in development.** This includes: +Компоненты, которые нарушают это правило, ведут себя непредсказуемо и вызывают ошибки. Чтобы помочь вам найти случайный нечистый код, строгий режим вызывает некоторые ваши функции (только те, которые должны быть чистыми) **дважды в режиме разработки.** Это включает: -- Your component function body (only top-level logic, so this doesn't include code inside event handlers) -- Functions that you pass to [`useState`](/reference/react/useState), [`set` functions](/reference/react/useState#setstate), [`useMemo`](/reference/react/useMemo), or [`useReducer`](/reference/react/useReducer) -- Some class component methods like [`constructor`](/reference/react/Component#constructor), [`render`](/reference/react/Component#render), [`shouldComponentUpdate`](/reference/react/Component#shouldcomponentupdate) ([see the whole list](https://reactjs.org/docs/strict-mode.html#detecting-unexpected-side-effects)) +- Тело компонента (только высокоуровневая логика, без учета кода внутри обработчиков событий) +- Функции, которые передаются в функции или хуки [`useState`](/reference/react/useState), [`set`](/reference/react/useState#setstate), [`useMemo`](/reference/react/useMemo), или [`useReducer`](/reference/react/useReducer) +- Некоторые методы классовых компонентов, такие как [`constructor`](/reference/react/Component#constructor), [`render`](/reference/react/Component#render), [`shouldComponentUpdate`](/reference/react/Component#shouldcomponentupdate) ([полный список](https://reactjs.org/docs/strict-mode.html#detecting-unexpected-side-effects)) -If a function is pure, running it twice does not change its behavior because a pure function produces the same result every time. However, if a function is impure (for example, it mutates the data it receives), running it twice tends to be noticeable (that's what makes it impure!) This helps you spot and fix the bug early. +Если функция является чистой, то ее двойной вызов не будет менять ее поведение, так как чистая функция выдает один и тот же результат каждый раз. Однако, если функция не является чистой (например, мутирует получаемые данные), ее двойной вызов будет заметным (именно это и делает ее нечистой!). Это поможет вам заметить и поправить баг заранее. -**Here is an example to illustrate how double rendering in Strict Mode helps you find bugs early.** +**Вот пример, который иллюстрирует, как повторный рендеринг в строгом режиме помогает вам находить баги на ранней стадии.** -This `StoryTray` component takes an array of `stories` and adds one last "Create Story" item at the end: +Компонент `StoryTray` принимает массив `stories` и добавляет в конец этого массива один элемент "Create Story": @@ -212,9 +212,9 @@ li { -There is a mistake in the code above. However, it is easy to miss because the initial output appears correct. +В коде выше есть ошибка. Однако ее легко пропустить, так как изначальный вывод выглядит правильным. -This mistake will become more noticeable if the `StoryTray` component re-renders multiple times. For example, let's make the `StoryTray` re-render with a different background color whenever you hover over it: +Ошибка будет более заметна, если компонент `StoryTray` будет отрендерен несколько раз. Например, давайте сделаем повторный рендеринг компонента `StoryTray` с другим цветом фона, когда наводим мышью: @@ -299,20 +299,20 @@ li { -Notice how every time you hover over the `StoryTray` component, "Create Story" gets added to the list again. The intention of the code was to add it once at the end. But `StoryTray` directly modifies the `stories` array from the props. Every time `StoryTray` renders, it adds "Create Story" again at the end of the same array. In other words, `StoryTray` is not a pure function--running it multiple times produces different results. +Обратите внимание, что каждый раз, когда мы наводим мышь на компонент `StoryTray`, "Create Story" добавляется в массив еще раз. Изначально требовалось добавить его лишь один раз в конец массива, но `StoryTray` напрямую мутирует массив `stories` из пропсов. Каждый раз, когда `StoryTray` рендерится, элемент "Create Story" опять добавляется в конец того же самого массива. Другими словами, `StoryTray` не является чистой функцией--при повторном рендеринге она возвращает разные результаты. -To fix this problem, you can make a copy of the array, and modify that copy instead of the original one: +Чтобы исправить эту проблему, нужно сделать копию массива и изменять ее, а не оригинальный массив: ```js {2} export default function StoryTray({ stories }) { - const items = stories.slice(); // Clone the array - // ✅ Good: Pushing into a new array + const items = stories.slice(); // Клонируем массив + // ✅ Хорошо: Добавляем элемент в новый массив items.push({ id: 'create', label: 'Create Story' }); ``` -This would [make the `StoryTray` function pure.](/learn/keeping-components-pure) Each time it is called, it would only modify a new copy of the array, and would not affect any external objects or variables. This solves the bug, but you had to make the component re-render more often before it became obvious that something is wrong with its behavior. +Так [компонент `StoryTray` станет чистым.](/learn/keeping-components-pure) Каждый раз, когда он вызывается, он будет только изменять новую копию массива и не будет влиять на внешние объекты или переменные. Это решает проблему, но вам нужно было сделать так, чтобы компонент чаще ре-рендерился, прежде чем стало очевидно, что его поведение некорректное. -**In the original example, the bug wasn't obvious. Now let's wrap the original (buggy) code in ``:** +**В оригинальном примере ошибка не была очевидной. Теперь давайте обернем исходный (с ошибкой) код в ``:** @@ -393,7 +393,7 @@ li { -**Strict Mode *always* calls your rendering function twice, so you can see the mistake right away** ("Create Story" appears twice). This lets you notice such mistakes early in the process. When you fix your component to render in Strict Mode, you *also* fix many possible future production bugs like the hover functionality from before: +**Строгий режим *всегда* вызывает рендеринг дважды, чтобы вы могли сразу увидеть ошибку** ("Create Story" появляется дважды). Это позволяет замечать такие ошибки на ранней стадии разработки. Когда вы заставляете ваш компонент рендерится в Strict Mode, вы *также* правите множество потенциальных багов продакшен-сборки, как например функциональность наведения мыши ниже: @@ -483,29 +483,29 @@ li { -Without Strict Mode, it was easy to miss the bug until you added more re-renders. Strict Mode made the same bug appear right away. Strict Mode helps you find bugs before you push them to your team and to your users. +Без строгого режима было легко пропустить ошибку, пока вы не добавили больше ре-рендеров. Строгий режим сразу показал ошибку. Он помогает вам находить баги перед тем, как вы отправите их вашей команде или пользователям. -[Read more about keeping components pure.](/learn/keeping-components-pure) +[Как сохранять компоненты чистыми.](/learn/keeping-components-pure) -If you have [React DevTools](/learn/react-developer-tools) installed, any `console.log` calls during the second render call will appear slightly dimmed. React DevTools also offers a setting (off by default) to suppress them completely. +Если у вас установлены [React DevTools](/learn/react-developer-tools), любые вызовы `console.log` во время повторного рендеринга будут выглядеть немного приглушенными. React DevTools также имеет настройку (выключена по умолчанию) для их полного отключения. --- -### Fixing bugs found by re-running Effects in development {/*fixing-bugs-found-by-re-running-effects-in-development*/} +### Исправление багов, найденных повторным вызовом эффекта в режиме разработки {/*fixing-bugs-found-by-re-running-effects-in-development*/} -Strict Mode can also help find bugs in [Effects.](/learn/synchronizing-with-effects) +Strict Mode также может помогать находить ошибки в [эффектах.](/learn/synchronizing-with-effects) -Every Effect has some setup code and may have some cleanup code. Normally, React calls setup when the component *mounts* (is added to the screen) and calls cleanup when the component *unmounts* (is removed from the screen). React then calls cleanup and setup again if its dependencies changed since the last render. +Каждый эффект имеет код установки и может иметь код для сброса эффекта. Обычно React вызывает код установки, когда компонент *монтируется* (добавляется на экран) и вызывает код сброса, когда компонент *размонтируется* (удаляется с экрана). React затем вызывает сбрасывающую и установку заново, если зависимости эффекта были изменены с момента последнего рендера. -When Strict Mode is on, React will also run **one extra setup+cleanup cycle in development for every Effect.** This may feel surprising, but it helps reveal subtle bugs that are hard to catch manually. +Когда строгий режим включен, React также вызовет **один дополнительный цикл установки и сброса для каждого эффекта в режиме разработки.** Это может быть неожиданным, но это помогает находить ошибки, которые сложно отловить вручную. -**Here is an example to illustrate how re-running Effects in Strict Mode helps you find bugs early.** +**Вот пример, иллюстрирующий то, как повторный вызов эффектов в строгом режиме помогает вам найти ошибки на ранней стадии.** -Consider this example that connects a component to a chat: +Рассмотрим пример, который подключает компонент к чату: @@ -562,9 +562,9 @@ button { margin-left: 10px; } -There is an issue with this code, but it might not be immediately clear. +В коде допущена ошибка, но это может быть неочевидно. -To make the issue more obvious, let's implement a feature. In the example below, `roomId` is not hardcoded. Instead, the user can select the `roomId` that they want to connect to from a dropdown. Click "Open chat" and then select different chat rooms one by one. Keep track of the number of active connections in the console: +Чтобы сделать проблему более явной, давайте добавим новую функциональность. В примере ниже, `roomId` не указана хардкодом. Вместо этого пользователь может выбрать `roomId`, к которому он хочет подключиться через выпадающее меню. Нажмите на "Open chat" и выберите разные чат-комнаты одну за одной. Обратите внимание на количество активных подключений в консоли: @@ -646,7 +646,7 @@ button { margin-left: 10px; } -You'll notice that the number of open connections always keeps growing. In a real app, this would cause performance and network problems. The issue is that [your Effect is missing a cleanup function:](/learn/synchronizing-with-effects#step-3-add-cleanup-if-needed) +Вы заметите, что число открытых подключений постоянно возрастает. В настоящем приложении это может вызывать проблемы с сетью и производительностью. Корень проблемы в том, что [в эффекте отсутствует сбрасывающая функция:](/learn/synchronizing-with-effects#step-3-add-cleanup-if-needed) ```js {4} useEffect(() => { @@ -656,9 +656,9 @@ You'll notice that the number of open connections always keeps growing. In a rea }, [roomId]); ``` -Now that your Effect "cleans up" after itself and destroys the outdated connections, the leak is solved. However, notice that the problem did not become visible until you've added more features (the select box). +Теперь, когда ваш эффект "очищается" и удаляет ненужные подключения, утечка устранена. Обратите внимание, что проблема не стала явной, пока вы не добавили больше функциональности (выпадающее меню). -**In the original example, the bug wasn't obvious. Now let's wrap the original (buggy) code in ``:** +**В исходном примере ошибка не была очевидной. Теперь давайте обернем исходный код (с ошибкой) в ``:** @@ -720,9 +720,9 @@ button { margin-left: 10px; } -**With Strict Mode, you immediately see that there is a problem** (the number of active connections jumps to 2). Strict Mode runs an extra setup+cleanup cycle for every Effect. This Effect has no cleanup logic, so it creates an extra connection but doesn't destroy it. This is a hint that you're missing a cleanup function. +**Благодаря строгому режиму вы сразу видите, что есть проблема** (количество активных подключений возрастает до 2). Строгий режим вызывает дополнительный цикл установки и сброса для каждого эффекта. У этого эффекта отсутствует логика сброса, поэтому он создает дополнительное подключение и не удаляет его. Это подсказка, что в эффекте отсутствует сбрасывающая функция. -Strict Mode lets you notice such mistakes early in the process. When you fix your Effect by adding a cleanup function in Strict Mode, you *also* fix many possible future production bugs like the select box from before: +Строгий режим позволяет вам замечать подобные ошибки на ранней стадии разработки. Когда вы поправите ваш эффект, добавив сбрасывающую функцию в строгом режиме, вы *также* поправите множество потенциальных багов продакшена, например, как выпадающее меню, которое мы рассматривали ранее: @@ -810,21 +810,21 @@ button { margin-left: 10px; } -Notice how the active connection count in the console doesn't keep growing anymore. +Обратите внимание, как количество активных подключений в консоли больше не растет. -Without Strict Mode, it was easy to miss that your Effect needed cleanup. By running *setup → cleanup → setup* instead of *setup* for your Effect in development, Strict Mode made the missing cleanup logic more noticeable. +Без строгого режима было легко пропустить, что у вашего эффекта отсутствует сбрасывающая функция. Благодаря вызову *установки → сброса → установки* вместо *установки* для вашего эффекта в режиме разработки, строгий режим сделал отсутствие сбрасывающей функции более заметной. -[Read more about implementing Effect cleanup.](/learn/synchronizing-with-effects#how-to-handle-the-effect-firing-twice-in-development) +[Узнать больше о сбрасывающей функции в эффекте.](/learn/synchronizing-with-effects#how-to-handle-the-effect-firing-twice-in-development) --- -### Fixing deprecation warnings enabled by Strict Mode {/*fixing-deprecation-warnings-enabled-by-strict-mode*/} +### Исправление предупреждений об устаревших методах в строгом режиме {/*fixing-deprecation-warnings-enabled-by-strict-mode*/} -React warns if some component anywhere inside a `` tree uses one of these deprecated APIs: +React предупреждает, если какой-либо компонент внутри дерева `` использует какое-либо из следующих устаревших API: -* [`findDOMNode`](/reference/react-dom/findDOMNode). [See alternatives.](https://reactjs.org/docs/strict-mode.html#warning-about-deprecated-finddomnode-usage) -* `UNSAFE_` class lifecycle methods like [`UNSAFE_componentWillMount`](/reference/react/Component#unsafe_componentwillmount). [See alternatives.](https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html#migrating-from-legacy-lifecycles) -* Legacy context ([`childContextTypes`](/reference/react/Component#static-childcontexttypes), [`contextTypes`](/reference/react/Component#static-contexttypes), and [`getChildContext`](/reference/react/Component#getchildcontext)). [See alternatives.](/reference/react/createContext) -* Legacy string refs ([`this.refs`](/reference/react/Component#refs)). [See alternatives.](https://reactjs.org/docs/strict-mode.html#warning-about-legacy-string-ref-api-usage) +* [`findDOMNode`](/reference/react-dom/findDOMNode). [Смотреть альтернативные решения.](https://reactjs.org/docs/strict-mode.html#warning-about-deprecated-finddomnode-usage) +* `UNSAFE_` классовые методы жизненного цикла, такие как [`UNSAFE_componentWillMount`](/reference/react/Component#unsafe_componentwillmount). [Смотреть альтернативные решения.](https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html#migrating-from-legacy-lifecycles) +* Устаревший контекст ([`childContextTypes`](/reference/react/Component#static-childcontexttypes), [`contextTypes`](/reference/react/Component#static-contexttypes), и[`getChildContext`](/reference/react/Component#getchildcontext)). [Смотреть альтернативные решения.](/reference/react/createContext) +* Устаревшие строковые рефы ([`this.refs`](/reference/react/Component#refs)). [Смотреть альтернативные решения.](https://reactjs.org/docs/strict-mode.html#warning-about-legacy-string-ref-api-usage) -These APIs are primarily used in older [class components](/reference/react/Component) so they rarely appear in modern apps. +Эти API в основном используются в старых [классовых компонентах](/reference/react/Component), поэтому они редко встречаются в современных приложениях. From da93812c7802e916d75bbb293889fda42c8d06aa Mon Sep 17 00:00:00 2001 From: Sami Romdhana <64911368+sami-romdhana@users.noreply.github.com> Date: Sun, 7 May 2023 00:06:40 +0200 Subject: [PATCH 131/233] Conditionally render offset div (#5997) Otherwise the address is being offset to the right when the refresh icon is not displayed --- src/components/Layout/HomeContent.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Layout/HomeContent.js b/src/components/Layout/HomeContent.js index 0597642ae..5ff366d31 100644 --- a/src/components/Layout/HomeContent.js +++ b/src/components/Layout/HomeContent.js @@ -1274,7 +1274,7 @@ function BrowserChrome({children, hasPulse, hasRefresh, domain, path}) {
            -
            + {hasRefresh &&
            }
            Date: Tue, 9 May 2023 19:49:50 +0200 Subject: [PATCH 132/233] add translation referencing-values-with-refs --- .../learn/referencing-values-with-refs.md | 158 +++++++++--------- 1 file changed, 79 insertions(+), 79 deletions(-) diff --git a/src/content/learn/referencing-values-with-refs.md b/src/content/learn/referencing-values-with-refs.md index da5d864ab..986b460a0 100644 --- a/src/content/learn/referencing-values-with-refs.md +++ b/src/content/learn/referencing-values-with-refs.md @@ -4,46 +4,45 @@ title: 'Referencing Values with Refs' -When you want a component to "remember" some information, but you don't want that information to [trigger new renders](/learn/render-and-commit), you can use a *ref*. +Для того, чтобы компонент "запомнил" какие-либо данные, но изменения этих данных не [вызывали новый рендер](/learn/render-and-commit), вы можете использовать *реф*. -- How to add a ref to your component -- How to update a ref's value -- How refs are different from state -- How to use refs safely +- Как добавлять реф в ваш компонент +- Как обновлять значение рефа +- Отличие рефа от состояния +- Как безопасно использовать рефы -## Adding a ref to your component {/*adding-a-ref-to-your-component*/} +## Добавляем реф в ваш компонент {/*adding-a-ref-to-your-component*/} -You can add a ref to your component by importing the `useRef` Hook from React: +Чтобы добавить реф в ваш компонент импортируйте хук `useRef` из React: ```js import { useRef } from 'react'; ``` -Inside your component, call the `useRef` Hook and pass the initial value that you want to reference as the only argument. For example, here is a ref to the value `0`: +Внутри компонента вызовите хук `useRef` и передайте аргумент, который будет являться начальным значением. Например, здесь значением реф является `0`: ```js const ref = useRef(0); ``` -`useRef` returns an object like this: - +`useRef` возвращает следующий объект: ```js -{ - current: 0 // The value you passed to useRef +{ + current: 0 // Значение, которое вы передали в useRef } ``` - + -You can access the current value of that ref through the `ref.current` property. This value is intentionally mutable, meaning you can both read and write to it. It's like a secret pocket of your component that React doesn't track. (This is what makes it an "escape hatch" from React's one-way data flow--more on that below!) +Получить доступ к значению рефа можно через свойство `ref.current`. Это значение намеренно является мутируемым, т.е. оно доступно как для чтения, так и для изменения. По сути, это как секретный карман, за которым React не следит. (Благодаря этому, реф является "лазейкой" в однонаправленном потоке данных React. Подробнее об этом ниже!) -Here, a button will increment `ref.current` on every click: +В примере ниже создадим кнопку, которая будет увеличивать `ref.current` на каждый клик: @@ -68,20 +67,20 @@ export default function Counter() { -The ref points to a number, but, like [state](/learn/state-a-components-memory), you could point to anything: a string, an object, or even a function. Unlike state, ref is a plain JavaScript object with the `current` property that you can read and modify. +Здесь реф ссылается на число, как и в случае с [состоянием](/learn/state-a-components-memory), вы можете ссылаться на что угодно: на строку, объект, или даже на функцию. В отличии от состояния, реф это обычный JavaScript объект со свойством `current`, которое можно читать и изменять. -Note that **the component doesn't re-render with every increment.** Like state, refs are retained by React between re-renders. However, setting state re-renders a component. Changing a ref does not! +Имейте в виду, что **изменение реф не вызовет повторный рендер на каждое изменение.** Рефы будут сохраняться между повторными рендерами, как и состояние. Однако, обновление состояние вызывает новый рендер. А изменение рефа нет! -## Example: building a stopwatch {/*example-building-a-stopwatch*/} +## Пример: создадим секундомер {/*example-building-a-stopwatch*/} -You can combine refs and state in a single component. For example, let's make a stopwatch that the user can start or stop by pressing a button. In order to display how much time has passed since the user pressed "Start", you will need to keep track of when the Start button was pressed and what the current time is. **This information is used for rendering, so you'll keep it in state:** +Рефы и состояние можно использовать в одном компоненте. Например, создадим секундомер, который можно будет запускать и останавливать нажатием кнопки. Чтобы отобразить сколько времени прошло с момента клика "Start", нужно следить за моментом клика и за текущим временем. **Так как эти данные используются при рендере, их лучше хранить в состоянии:** ```js const [startTime, setStartTime] = useState(null); const [now, setNow] = useState(null); ``` -When the user presses "Start", you'll use [`setInterval`](https://developer.mozilla.org/docs/Web/API/setInterval) in order to update the time every 10 milliseconds: +Чтобы обновлять время каждые 10 миллисекунд, после того как пользователь нажимает "Start", будем использовать [`setInterval`](https://developer.mozilla.org/docs/Web/API/setInterval): @@ -93,12 +92,12 @@ export default function Stopwatch() { const [now, setNow] = useState(null); function handleStart() { - // Start counting. + // Начинаем отсчёт. setStartTime(Date.now()); setNow(Date.now()); setInterval(() => { - // Update the current time every 10ms. + // Обновляем текущее время каждые 10мс. setNow(Date.now()); }, 10); } @@ -121,7 +120,7 @@ export default function Stopwatch() { -When the "Stop" button is pressed, you need to cancel the existing interval so that it stops updating the `now` state variable. You can do this by calling [`clearInterval`](https://developer.mozilla.org/en-US/docs/Web/API/clearInterval), but you need to give it the interval ID that was previously returned by the `setInterval` call when the user pressed Start. You need to keep the interval ID somewhere. **Since the interval ID is not used for rendering, you can keep it in a ref:** +Когда нажата кнопка "Stop", нужно очистить текущий интервал, чтобы значение состояния `now` перестало обновляться. Для реализации можно использовать вызов[`clearInterval`](https://developer.mozilla.org/en-US/docs/Web/API/clearInterval), но интервалу нужно задать ID, которое возвращается при вызове `setInterval`, когда пользователь нажал "Start". ID интервала нужно где-то сохранить. **Мы можем сохранить его в реф, т.к. он никак не влияет на рендер:** @@ -168,20 +167,20 @@ export default function Stopwatch() { -When a piece of information is used for rendering, keep it in state. When a piece of information is only needed by event handlers and changing it doesn't require a re-render, using a ref may be more efficient. +Когда какие-то данные используются для рендера, используйте состояние. Когда данные нужны только для обработчиков событий и изменение этих дынных не требуют повторного рендера, использование реф будет более эффективным. -## Differences between refs and state {/*differences-between-refs-and-state*/} +## Отличие рефа от состояния {/*differences-between-refs-and-state*/} -Perhaps you're thinking refs seem less "strict" than state—you can mutate them instead of always having to use a state setting function, for instance. But in most cases, you'll want to use state. Refs are an "escape hatch" you won't need often. Here's how state and refs compare: +Может показаться, что рефы менее "строгие" чем состояние—их можно изменять напрямую, вместо использования функции для обновления состояния. Но в большинстве случаев, вам захочется использовать состояние. Рефы—это "лазейка", которую не рекомендуется использовать слишком часто. Ниже сравнение рефа и состояния: -| refs | state | +| refs | state | | ------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | -| `useRef(initialValue)` returns `{ current: initialValue }` | `useState(initialValue)` returns the current value of a state variable and a state setter function ( `[value, setValue]`) | -| Doesn't trigger re-render when you change it. | Triggers re-render when you change it. | -| Mutable—you can modify and update `current`'s value outside of the rendering process. | "Immutable"—you must use the state setting function to modify state variables to queue a re-render. | -| You shouldn't read (or write) the `current` value during rendering. | You can read state at any time. However, each render has its own [snapshot](/learn/state-as-a-snapshot) of state which does not change. +| `useRef(initialValue)` возвращает `{ current: initialValue }` | `useState(initialValue)` возвращает текущее значение состояния и функцию-сеттер для его обновления ( `[value, setValue]`) | +| При изменении не вызывает повторный рендер. | При изменении вызывает повторный рендер. | +| Мутабельный—можно изменять и обновлять значение `current` независимо от процесса рендера. | "Иммутабельный"—обязательно использовать функцию -сеттер, чтобы добавить изменение состояния в очередь обновлений. | +| Не рекомендуется читать (или изменять) значение `current` во время рендера. | Можно читать значение состояния в любое время. Однако, за каждым рендером закреплён свой [снимок](/learn/state-as-a-snapshot) состояния, который не будет изменяться. -Here is a counter button that's implemented with state: +В следующем примере создадим кнопку счётчика, которая использует состояние: @@ -205,9 +204,9 @@ export default function Counter() { -Because the `count` value is displayed, it makes sense to use a state value for it. When the counter's value is set with `setCount()`, React re-renders the component and the screen updates to reflect the new count. +В этом случае имеет смысл использовать состояние, т.к. значение `count` отображается на странице. Когда состояние счётчика обновляется при помощи `setCount()`, React вызывает повторный рендер и на экране отображается новое значение счётчика. -If you tried to implement this with a ref, React would never re-render the component, so you'd never see the count change! See how clicking this button **does not update its text**: +Если использовать реф, React никогда не вызовет повторный рендер, поэтому вы никогда не увидите изменение счётчика! Например, в данном случае клик по кнопке **не обновляет её текст**: @@ -218,7 +217,7 @@ export default function Counter() { let countRef = useRef(0); function handleClick() { - // This doesn't re-render the component! + // Повторный рендер не вызовется! countRef.current = countRef.current + 1; } @@ -232,68 +231,69 @@ export default function Counter() { -This is why reading `ref.current` during render leads to unreliable code. If you need that, use state instead. +Именно поэтому, чтение из `ref.current` во время рендера приводит к непредсказуемому результату. Используйте состояние, если во время рендера вам точно нужно читать данные из него! -#### How does useRef work inside? {/*how-does-use-ref-work-inside*/} +#### Как работает useRef изнутри? {/*how-does-use-ref-work-inside*/} -Although both `useState` and `useRef` are provided by React, in principle `useRef` could be implemented _on top of_ `useState`. You can imagine that inside of React, `useRef` is implemented like this: +Хотя оба хука `useState` и `useRef` могут быть импортированы из React, `useRef` может быть реализован поверх `useState`. Можно представлять, что внутри React, `useRef` реализован следующим образом: ```js -// Inside of React +// Внутри React function useRef(initialValue) { const [ref, unused] = useState({ current: initialValue }); return ref; } ``` -During the first render, `useRef` returns `{ current: initialValue }`. This object is stored by React, so during the next render the same object will be returned. Note how the state setter is unused in this example. It is unnecessary because `useRef` always needs to return the same object! +Во время первого рендера, `useRef` возвращает `{ current: initialValue }`. Этот объект сохраняется внутри React, поэтому во время следующего рендера вернётся точно такой же объект. Обратите внимание, что функция для обновления состояния в этом примере не используется. В этом нет необходимости, т.к. `useRef` всегда возвращает один и тот же объект! -React provides a built-in version of `useRef` because it is common enough in practice. But you can think of it as a regular state variable without a setter. If you're familiar with object-oriented programming, refs might remind you of instance fields--but instead of `this.something` you write `somethingRef.current`. +React предоставляет встроенный хук `useRef`, т.к. это достаточно часто встречается на практике. Но можно представлять себе, что это обычное значение состояния, но без функции обновления. Если вы знакомы с объектно-ориентированным программированием, рефы могут напоминать вам поля экземпляра--но вместо `this.something` используется `somethingRef.current`. -## When to use refs {/*when-to-use-refs*/} +## Когда использовать рефы {/*when-to-use-refs*/} + +Как правило, вы будете использовать реф, когда захотите выйти за пределы парадигмы React и иметь возможность взаимодействовать со сторонними API—часто это API браузера, которое никак не влияет на отображение компонента на странице. Ниже приведены примеры таких ситуаций: -Typically, you will use a ref when your component needs to "step outside" React and communicate with external APIs—often a browser API that won't impact the appearance of the component. Here are a few of these rare situations: +- Хранение [ID таймера](https://developer.mozilla.org/docs/Web/API/setTimeout) +- Хранение и манипулирование [DOM-элементами](https://developer.mozilla.org/docs/Web/API/Element), которое мы разберём [в следующей главе](/learn/manipulating-the-dom-with-refs) +- Хранение различных других объектов, которые не влияют на JSX. -- Storing [timeout IDs](https://developer.mozilla.org/docs/Web/API/setTimeout) -- Storing and manipulating [DOM elements](https://developer.mozilla.org/docs/Web/API/Element), which we cover on [the next page](/learn/manipulating-the-dom-with-refs) -- Storing other objects that aren't necessary to calculate the JSX. +Если вы хотите сохранить какое-то значение внутри компонента, которое не влияет на логику рендера, используйте реф. -If your component needs to store some value, but it doesn't impact the rendering logic, choose refs. +## ## Рекомендации по использованию рефов {/*best-practices-for-refs*/} -## Best practices for refs {/*best-practices-for-refs*/} +Следуйте следующим принципам, чтобы сделать ваши компоненты более предсказуемыми: -Following these principles will make your components more predictable: +- **Используйте рефы как лазейку.** Использование рефов является оправданным, когда вы работаете со сторонними системами или с API браузера. Если большая часть логики вашего приложения и потока данных зависит от рефов, скорее всего вам стоит переосмыслить свой подход. +- **Не читайте и не изменяйте `ref.current` во время рендера.** Если необходимо использовать какие-то данные во время рендера, используйте [состояние](/learn/state-a-components-memory) вместо рефа. Даже просто чтение во время рендера делает поведение вашего компонента менее предсказуемым, поскольку React ничего не знает об изменении `ref.current`. (Единственным исключением является `if (!ref.current) ref.current = new Thing()`, где реф устанавливается единожды во время первого рендера.) -- **Treat refs as an escape hatch.** Refs are useful when you work with external systems or browser APIs. If much of your application logic and data flow relies on refs, you might want to rethink your approach. -- **Don't read or write `ref.current` during rendering.** If some information is needed during rendering, use [state](/learn/state-a-components-memory) instead. Since React doesn't know when `ref.current` changes, even reading it while rendering makes your component's behavior difficult to predict. (The only exception to this is code like `if (!ref.current) ref.current = new Thing()` which only sets the ref once during the first render.) -Limitations of React state don't apply to refs. For example, state acts like a [snapshot for every render](/learn/state-as-a-snapshot) and [doesn't update synchronously.](/learn/queueing-a-series-of-state-updates) But when you mutate the current value of a ref, it changes immediately: +Ограничения React при использовании состояния никак не влияют на рефы. Например, состояние ведёт себя как [снимок для каждого рендера](/learn/state-as-a-snapshot) и [не обновляется синхронно.](/learn/queueing-a-series-of-state-updates) Но при изменении текущего значения реф, оно изменяется сразу же: ```js ref.current = 5; console.log(ref.current); // 5 ``` -This is because **the ref itself is a regular JavaScript object,** and so it behaves like one. +Это обусловлено тем, что **реф—это обычный JavaScript объект,** и ведёт себя как объект. -You also don't need to worry about [avoiding mutation](/learn/updating-objects-in-state) when you work with a ref. As long as the object you're mutating isn't used for rendering, React doesn't care what you do with the ref or its contents. +Когда вы работаете с рефами, вам не нужно беспокоится о том, чтобы [избегать мутаций](/learn/updating-objects-in-state). До тех пор пока объект, который вы мутируете не используется для рендера, React нет дела, что вы делаете с рефами и их значениями. -## Refs and the DOM {/*refs-and-the-dom*/} +## Рефы и DOM {/*refs-and-the-dom*/} -You can point a ref to any value. However, the most common use case for a ref is to access a DOM element. For example, this is handy if you want to focus an input programmatically. When you pass a ref to a `ref` attribute in JSX, like `
            `, React will put the corresponding DOM element into `myRef.current`. You can read more about this in [Manipulating the DOM with Refs.](/learn/manipulating-the-dom-with-refs) +Вы можете использовать реф в качестве ссылки на любое значение. Однако, на практике рефы часто используются для доступа к DOM-элементам. Например, когда нужно программно сфокусироваться на элементе `input`. Когда вы устанавливаете `ref` через атрибут, `
            `, React сохранит соответствующий DOM-элемент в качестве значения `myRef.current`. Вы можете больше прочитать об этом в [Manipulating the DOM with Refs.](/learn/manipulating-the-dom-with-refs). -- Refs are an escape hatch to hold onto values that aren't used for rendering. You won't need them often. -- A ref is a plain JavaScript object with a single property called `current`, which you can read or set. -- You can ask React to give you a ref by calling the `useRef` Hook. -- Like state, refs let you retain information between re-renders of a component. -- Unlike state, setting the ref's `current` value does not trigger a re-render. -- Don't read or write `ref.current` during rendering. This makes your component hard to predict. +- Рефы это лазейка для хранения значений, которые не используются при рендере. Чаще всего вы можете обойтись без них. +- Реф—это обычный JavaScript объект с единственным свойством `curent`, которое доступно как для чтения, так и для записи. +- Вы можете использовать реф, вызвав хук `useRef` из React. +- Рефы позволяют вам сохранить данные между перерисовками компонента, как и в случае с состоянием. +- В отличии от состояния, запись нового значения в `ref.current` не спровоцирует повторный рендер компонента. +- Не читайте и не записывайте ничего в `ref.current` во время рендера. Это сделает поведение вашего компонента менее предсказуемым. @@ -301,13 +301,13 @@ You can point a ref to any value. However, the most common use case for a ref is -#### Fix a broken chat input {/*fix-a-broken-chat-input*/} +#### Исправьте неработающий input в чате {/*fix-a-broken-chat-input*/} -Type a message and click "Send". You will notice there is a three second delay before you see the "Sent!" alert. During this delay, you can see an "Undo" button. Click it. This "Undo" button is supposed to stop the "Sent!" message from appearing. It does this by calling [`clearTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/clearTimeout) for the timeout ID saved during `handleSend`. However, even after "Undo" is clicked, the "Sent!" message still appears. Find why it doesn't work, and fix it. +Введите сообщение и нажмите "Send". Можно заметить трёхсекундную задержку перед тем как появится модальное окно с сообщением "Sent!". Во время этой задержки появляется кнопка "Undo". Кликните по ней. Предполагается, что кнопка "Undo" предотвратит появление сообщения "Sent!". Это происходит из-за вызова [`clearTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/clearTimeout) для сохранения ID во время `handleSend`. Однако, даже после клика "Undo", сообщение все ещё появляется. Попробуйте разобраться, почему этот код не работает и исправить его. -Regular variables like `let timeoutID` don't "survive" between re-renders because every render runs your component (and initializes its variables) from scratch. Should you keep the timeout ID somewhere else? +Обычные переменные, такие как `let timeoutID` не "выживают" между повторными рендерами, потому что каждый рендер запускает компонент (и инициализирует переменные) с нуля. @@ -360,7 +360,7 @@ export default function Chat() { -Whenever your component re-renders (such as when you set state), all local variables get initialized from scratch. This is why you can't save the timeout ID in a local variable like `timeoutID` and then expect another event handler to "see" it in the future. Instead, store it in a ref, which React will preserve between renders. +Каждый раз когда компонент рендерится повторно (например, когда устанавливается новое состояние), все локальные переменные инициализируются с нуля. Поэтому вы не можете сохранить ID таймера в обычную переменную такую, как `timeoutID` и ожидать, что обработчик сможет "увидеть" её в будущем. Вместо этого сохраните её в реф, который React сохраняет между рендерами. @@ -412,9 +412,9 @@ export default function Chat() { -#### Fix a component failing to re-render {/*fix-a-component-failing-to-re-render*/} +#### Исправьте ошибку при повторном рендере компонента {/*fix-a-component-failing-to-re-render*/} -This button is supposed to toggle between showing "On" and "Off". However, it always shows "Off". What is wrong with this code? Fix it. +Предполагается, что кнопка должна переключаться между отображением "On" и "Off". Но всегда отображается "Off". Что не так с эти кодом? Попробуйте исправить. @@ -438,7 +438,7 @@ export default function Toggle() { -In this example, the current value of a ref is used to calculate the rendering output: `{isOnRef.current ? 'On' : 'Off'}`. This is a sign that this information should not be in a ref, and should have instead been put in state. To fix it, remove the ref and use state instead: +В этом примере текущее значение реф используется для вычисления того, что отобразится на странице: `{isOnRef.current ? 'On' : 'Off'}`. Это признак того, что эти данные не должны хранится в рефе, и вместо этого, должны храниться в состоянии. Чтобы исправить, удалите реф и используйте состояние вместо него: @@ -462,17 +462,17 @@ export default function Toggle() { -#### Fix debouncing {/*fix-debouncing*/} +#### Исправьте debouncing {/*fix-debouncing*/} -In this example, all button click handlers are ["debounced".](https://redd.one/blog/debounce-vs-throttle) To see what this means, press one of the buttons. Notice how the message appears a second later. If you press the button while waiting for the message, the timer will reset. So if you keep clicking the same button fast many times, the message won't appear until a second *after* you stop clicking. Debouncing lets you delay some action until the user "stops doing things". +В данном примере все обработчики событий для кнопок являются ["debounced".](https://redd.one/blog/debounce-vs-throttle) Чтобы понять, как это работает, кликните на одну из кнопок. Обратите внимание, что сообщение появляется через секунду. Если нажать на кнопку во время ожидания сообщения, таймер сбросится. Таким образом, если вы продолжите кликать одну и ту же кнопку много раз, сообщение не появится до тех пор, пока не пройдёт секунда _после_ последнего клика. Debouncing позволяет вам установить задержку до тех пор, пока пользователь "не прекратит делать что-то", прежде чем произойдёт какое-то действие. -This example works, but not quite as intended. The buttons are not independent. To see the problem, click one of the buttons, and then immediately click another button. You'd expect that after a delay, you would see both button's messages. But only the last button's message shows up. The first button's message gets lost. +Этот пример работает, но не совсем как было задумано. Кнопки не являются независимыми. Чтобы увидеть проблему, кликните на одну из кнопок и затем кликните на другую кнопку. Мы ожидаем увидеть два сообщения, которые привязаны к каждой кнопке. Но мы увидим только сообщение последней. Сообщение первой кнопки потерялось. -Why are the buttons interfering with each other? Find and fix the issue. +Почему кнопки конфликтуют между собой? Попробуйте найти и исправить проблему. -The last timeout ID variable is shared between all `DebouncedButton` components. This is why clicking one button resets another button's timeout. Can you store a separate timeout ID for each button? +Последний ID таймера используется во всех компонентах `DebouncedButton`. В этом причина того, что клик по одной кнопке сбрасывает таймер другой. Можно ли хранить ID таймера отдельно для каждой из кнопок? @@ -525,7 +525,7 @@ button { display: block; margin: 10px; } -A variable like `timeoutID` is shared between all components. This is why clicking on the second button resets the first button's pending timeout. To fix this, you can keep timeout in a ref. Each button will get its own ref, so they won't conflict with each other. Notice how clicking two buttons fast will show both messages. +Переменная `timeoutID` была использована во всех компонентах. Поэтому клик по второй кнопке сбрасывал таймер ожидания первой. Чтобы это исправить, следует хранить таймер в рефе. Каждая кнопка получит свой реф и вместе кнопки будут работать корректно. Обратите внимание, что быстрый клик по двум кнопкам покажет оба сообщения. @@ -577,11 +577,11 @@ button { display: block; margin: 10px; } -#### Read the latest state {/*read-the-latest-state*/} +#### Прочитайте самое новое состояние {/*read-the-latest-state*/} -In this example, after you press "Send", there is a small delay before the message is shown. Type "hello", press Send, and then quickly edit the input again. Despite your edits, the alert would still show "hello" (which was the value of state [at the time](/learn/state-as-a-snapshot#state-over-time) the button was clicked). +В данном примере, после нажатия "Send" есть небольшая задержка прежде, чем появится сообщение. Введите "hello", нажмите Send, и потом снова отредактируйте поле ввода. Несмотря на редактирование, модальное окно все ещё показывает "hello" (эта строка была значением состояния [во время](/learn/state-as-a-snapshot#state-over-time), когда произошёл клик по кнопке). -Usually, this behavior is what you want in an app. However, there may be occasional cases where you want some asynchronous code to read the *latest* version of some state. Can you think of a way to make the alert show the *current* input text rather than what it was at the time of the click? +Как правило, именно такое поведение вам необходимо в вашем приложении. Тем не менее, могут возникнуть случаи, когда будет необходимость получить доступ к самой _последней_ версии состояния в каком-либо асинхронном коде. Можете ли вы найти решение, чтобы модальное окно показывало _текущий_ текст поля ввода, вместо состояния, которое сохранилось во время клика? @@ -616,7 +616,7 @@ export default function Chat() { -State works [like a snapshot](/learn/state-as-a-snapshot), so you can't read the latest state from an asynchronous operation like a timeout. However, you can keep the latest input text in a ref. A ref is mutable, so you can read the `current` property at any time. Since the current text is also used for rendering, in this example, you will need *both* a state variable (for rendering), *and* a ref (to read it in the timeout). You will need to update the current ref value manually. +Состояние работает как [снимок](/learn/state-as-a-snapshot), поэтому вы не сможете получить доступ к его последней версии из асинхронного кода, например внутри таймера. Однако, вы можете хранить последнее значение поля ввода в рефе. Реф является мутируемым, поэтому свойство `current` доступно для чтения в любое время. Поскольку, в этом примере, введённый текст также используется для рендера, вам необходимо использовать и *состояние* переменной (для рендера), и *реф* (для чтения внутри таймера). Обновляйте текущий реф вручную. From 8c4dc0619b3e3939b84a5011f127e7d763121299 Mon Sep 17 00:00:00 2001 From: Maryna Darashuk <59647513+maridoroshuk@users.noreply.github.com> Date: Wed, 10 May 2023 21:26:15 +0200 Subject: [PATCH 133/233] fix typo --- src/content/learn/referencing-values-with-refs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/referencing-values-with-refs.md b/src/content/learn/referencing-values-with-refs.md index 986b460a0..6bb73f7fd 100644 --- a/src/content/learn/referencing-values-with-refs.md +++ b/src/content/learn/referencing-values-with-refs.md @@ -263,7 +263,7 @@ React предоставляет встроенный хук `useRef`, т.к. э Если вы хотите сохранить какое-то значение внутри компонента, которое не влияет на логику рендера, используйте реф. -## ## Рекомендации по использованию рефов {/*best-practices-for-refs*/} +## Рекомендации по использованию рефов {/*best-practices-for-refs*/} Следуйте следующим принципам, чтобы сделать ваши компоненты более предсказуемыми: From ebc45f563e9612df7b485ad82324225d554c625b Mon Sep 17 00:00:00 2001 From: Viacheslav Makarov <9768704+mekarthedev@users.noreply.github.com> Date: Fri, 12 May 2023 18:15:37 +0200 Subject: [PATCH 134/233] Remove unnecessary backticks breaking markdown highlighting (#6025) --- src/content/learn/removing-effect-dependencies.md | 4 ++-- src/content/learn/separating-events-from-effects.md | 6 +++--- src/content/learn/updating-objects-in-state.md | 2 +- src/content/reference/react-dom/client/createRoot.md | 4 ++-- src/content/reference/react-dom/client/hydrateRoot.md | 2 +- src/content/reference/react-dom/hydrate.md | 2 +- src/content/reference/react-dom/render.md | 2 +- src/content/reference/react-dom/unmountComponentAtNode.md | 2 +- src/content/reference/react/cloneElement.md | 2 +- src/content/reference/react/createContext.md | 2 +- src/content/reference/react/useEffect.md | 2 +- 11 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/content/learn/removing-effect-dependencies.md b/src/content/learn/removing-effect-dependencies.md index dc34eedad..0a5151daa 100644 --- a/src/content/learn/removing-effect-dependencies.md +++ b/src/content/learn/removing-effect-dependencies.md @@ -882,7 +882,7 @@ const options2 = { serverUrl: 'https://localhost:1234', roomId: 'music' }; // These are two different objects! console.log(Object.is(options1, options2)); // false -```` +``` **Object and function dependencies can make your Effect re-synchronize more often than you need.** @@ -968,7 +968,7 @@ const roomId2 = 'music'; // These two strings are the same! console.log(Object.is(roomId1, roomId2)); // true -```` +``` Thanks to this fix, the chat no longer re-connects if you edit the input: diff --git a/src/content/learn/separating-events-from-effects.md b/src/content/learn/separating-events-from-effects.md index e932e8afd..a897a602b 100644 --- a/src/content/learn/separating-events-from-effects.md +++ b/src/content/learn/separating-events-from-effects.md @@ -239,7 +239,7 @@ function ChatRoom({ roomId, theme }) { }); connection.connect(); // ... -```` +``` However, `theme` is a reactive value (it can change as a result of re-rendering), and [every reactive value read by an Effect must be declared as its dependency.](/learn/lifecycle-of-reactive-effects#react-verifies-that-you-specified-every-reactive-value-as-a-dependency) Now you have to specify `theme` as a dependency of your Effect: @@ -256,7 +256,7 @@ function ChatRoom({ roomId, theme }) { }; }, [roomId, theme]); // ✅ All dependencies declared // ... -```` +``` Play with this example and see if you can spot the problem with this user experience: @@ -416,7 +416,7 @@ function ChatRoom({ roomId, theme }) { showNotification('Connected!', theme); }); // ... -```` +``` Here, `onConnected` is called an *Effect Event.* It's a part of your Effect logic, but it behaves a lot more like an event handler. The logic inside it is not reactive, and it always "sees" the latest values of your props and state. diff --git a/src/content/learn/updating-objects-in-state.md b/src/content/learn/updating-objects-in-state.md index 1e23c8d3d..9289f2454 100644 --- a/src/content/learn/updating-objects-in-state.md +++ b/src/content/learn/updating-objects-in-state.md @@ -184,7 +184,7 @@ const nextPosition = {}; nextPosition.x = e.clientX; nextPosition.y = e.clientY; setPosition(nextPosition); -```` +``` In fact, it is completely equivalent to writing this: diff --git a/src/content/reference/react-dom/client/createRoot.md b/src/content/reference/react-dom/client/createRoot.md index 9121e1d78..d91bc20c6 100644 --- a/src/content/reference/react-dom/client/createRoot.md +++ b/src/content/reference/react-dom/client/createRoot.md @@ -133,7 +133,7 @@ import { createRoot } from 'react-dom/client'; const root = createRoot(document.getElementById('root')); root.render(); -```` +``` Usually, you only need to run this code once at startup. It will: @@ -395,7 +395,7 @@ root.render(App); // ✅ Correct: is a component. root.render(); -```` +``` Or if you pass a function to `root.render`, instead of the result of calling it: diff --git a/src/content/reference/react-dom/client/hydrateRoot.md b/src/content/reference/react-dom/client/hydrateRoot.md index c875560da..db558bb80 100644 --- a/src/content/reference/react-dom/client/hydrateRoot.md +++ b/src/content/reference/react-dom/client/hydrateRoot.md @@ -127,7 +127,7 @@ If your app's HTML was generated by [`react-dom/server`](/reference/react-dom/cl import { hydrateRoot } from 'react-dom/client'; hydrateRoot(document.getElementById('root'), ); -```` +``` This will hydrate the server HTML inside the browser DOM node with the React component for your app. Usually, you will do it once at startup. If you use a framework, it might do this behind the scenes for you. diff --git a/src/content/reference/react-dom/hydrate.md b/src/content/reference/react-dom/hydrate.md index ab036caa1..639c7ab25 100644 --- a/src/content/reference/react-dom/hydrate.md +++ b/src/content/reference/react-dom/hydrate.md @@ -68,7 +68,7 @@ Call `hydrate` to attach a React component into a import { hydrate } from 'react-dom'; hydrate(, document.getElementById('root')); -```` +``` Using `hydrate()` to render a client-only app (an app without server-rendered HTML) is not supported. Use [`render()`](/reference/react-dom/render) (in React 17 and below) or [`createRoot()`](/reference/react-dom/client/createRoot) (in React 18+) instead. diff --git a/src/content/reference/react-dom/render.md b/src/content/reference/react-dom/render.md index 1a3baead7..a0f751278 100644 --- a/src/content/reference/react-dom/render.md +++ b/src/content/reference/react-dom/render.md @@ -77,7 +77,7 @@ import { render } from 'react-dom'; import App from './App.js'; render(, document.getElementById('root')); -```` +``` ### Rendering the root component {/*rendering-the-root-component*/} diff --git a/src/content/reference/react-dom/unmountComponentAtNode.md b/src/content/reference/react-dom/unmountComponentAtNode.md index e538ceb34..12f11dc74 100644 --- a/src/content/reference/react-dom/unmountComponentAtNode.md +++ b/src/content/reference/react-dom/unmountComponentAtNode.md @@ -64,7 +64,7 @@ render(, rootNode); // ... unmountComponentAtNode(rootNode); -```` +``` ### Removing a React app from a DOM element {/*removing-a-react-app-from-a-dom-element*/} diff --git a/src/content/reference/react/cloneElement.md b/src/content/reference/react/cloneElement.md index 86711f4d8..d6ef84b0a 100644 --- a/src/content/reference/react/cloneElement.md +++ b/src/content/reference/react/cloneElement.md @@ -427,7 +427,7 @@ With this approach, `Row` does not need to receive an `isHighlighted` prop at al export default function Row({ title }) { const isHighlighted = useContext(HighlightContext); // ... -```` +``` This allows the calling component to not know or worry about passing `isHighlighted` to ``: diff --git a/src/content/reference/react/createContext.md b/src/content/reference/react/createContext.md index ff9032aac..a653633c1 100644 --- a/src/content/reference/react/createContext.md +++ b/src/content/reference/react/createContext.md @@ -166,7 +166,7 @@ import { createContext } from 'react'; export const ThemeContext = createContext('light'); export const AuthContext = createContext(null); -```` +``` Components declared in other files can then use the [`import`](https://developer.mozilla.org/en-US/docs/web/javascript/reference/statements/import) statement to read or provide this context: diff --git a/src/content/reference/react/useEffect.md b/src/content/reference/react/useEffect.md index 8614991ca..dd84fd2ea 100644 --- a/src/content/reference/react/useEffect.md +++ b/src/content/reference/react/useEffect.md @@ -531,7 +531,7 @@ function ChatRoom({ roomId }) { serverUrl: serverUrl }); // ... -```` +``` There are also many excellent custom Hooks for every purpose available in the React ecosystem. From 8e5566a45e7e30c71533e4af776b6a1d7eaaea9c Mon Sep 17 00:00:00 2001 From: Jana Korichneva Date: Fri, 12 May 2023 22:25:04 +0400 Subject: [PATCH 135/233] fix code review comments --- src/content/reference/react/StrictMode.md | 180 +++++++++++----------- 1 file changed, 90 insertions(+), 90 deletions(-) diff --git a/src/content/reference/react/StrictMode.md b/src/content/reference/react/StrictMode.md index 320d190a3..bdfa1ec9a 100644 --- a/src/content/reference/react/StrictMode.md +++ b/src/content/reference/react/StrictMode.md @@ -5,7 +5,7 @@ title: -`` позволяет находить распространенные баги в компонентах на ранней стадии разработки. +`` позволяет вам обнаружить распространенные баги в ваших компонентах на ранних этапах разработки. ```js @@ -24,7 +24,7 @@ title: ### `` {/*strictmode*/} -Используйте `StrictMode`, чтобы включить дополнительные проверки и предупреждения для потомков дерева компонентов: +Используйте `StrictMode`, для активации дополнительных проверок и предупреждений для вложенного дерева компонентов: ```js import { StrictMode } from 'react'; @@ -40,10 +40,10 @@ root.render( [Больше примеров использования.](#usage) -Строгий режим активирует следующее поведение в режиме разработки: +Строгий режим активирует следующие поведения в режиме разработки: -- Ваши компоненты будут [рендерится повторно](#fixing-bugs-found-by-double-rendering-in-development) чтобы можно было найти баги, вызванные нечистым рендерингом. -- Ваши компоненты будут [повторно запускать эффекты](#fixing-bugs-found-by-re-running-effects-in-development), чтобы можно было найти баги возникающие из-за отсутствия сбрасывающей функции в эффекте. +- Ваши компоненты будут [рендерится повторно](#fixing-bugs-found-by-double-rendering-in-development), чтобы можно было найти баги, вызванные нечистым рендерингом. +- Ваши компоненты будут [повторно запускать эффекты](#fixing-bugs-found-by-re-running-effects-in-development), чтобы можно было найти баги, возникающие из-за отсутствия сброса эффекта. - Ваши компоненты будут [проверяться на использование устаревших API.](#fixing-deprecation-warnings-enabled-by-strict-mode) #### Пропсы {/*props*/} @@ -52,7 +52,7 @@ root.render( #### Предостережения {/*caveats*/} -* Если ваше дерево обернуто в ``, то сделать исключение из строгого режима невозможно. Это дает вам уверенность, что все компоненты внутри `` будут проверены. Если две команды работают над одним продуктом и не могут прийти к соглашению, нужны ли им эти проверки, то нужно или достичь компромисса, или переместить `` ниже по дереву. +* Если вы используете ``, то не сможете отключить его для части дерева. Это гарантирует, что все компоненты внутри `` проходят проверки. Если две команды, работающие над продуктом, не могут прийти к соглашению, нужны ли им эти проверки, то они должны либо достичь компромисса, либо переместить `` ниже по дереву. --- @@ -85,9 +85,9 @@ root.render( Строгий режим включает следующие дополнительные проверки в режиме разработки: -- Ваши компоненты будут [рендерится повторно](#fixing-bugs-found-by-double-rendering-in-development) чтобы можно было найти баги, вызванные нечистым рендерингом. -- Ваши компоненты будут [повторно запускать эффекты](#fixing-bugs-found-by-re-running-effects-in-development) чтобы можно было найти баги возникающие из-за отсутствия сбрасывающей функции в эффекте. -- Ваши компоненты будут [проверяться на использование устаревших APIs.](#fixing-deprecation-warnings-enabled-by-strict-mode) +- Ваши компоненты будут [рендерится повторно](#fixing-bugs-found-by-double-rendering-in-development), чтобы можно было найти баги, вызванные нечистым рендерингом. +- Ваши компоненты будут [повторно запускать эффекты](#fixing-bugs-found-by-re-running-effects-in-development), чтобы можно было найти баги, возникающие из-за отсутствия сброса эффекта. +- Ваши компоненты будут [проверяться на использование устаревших API.](#fixing-deprecation-warnings-enabled-by-strict-mode) **Все эти проверки работают только в режиме разработки и не оказывают никакого эффекта в продакшен-сборке.** @@ -95,9 +95,9 @@ root.render( --- -### Как включить строгий режим для части приложения {/*enabling-strict-mode-for-a-part-of-the-app*/} +### Активация строгого режима для части приложения {/*enabling-strict-mode-for-a-part-of-the-app*/} -Строгий режим может быть включён для любой части вашего приложения: +Вы можете активировать строгий режим для любой части вашего приложения: ```js {7,12} import { StrictMode } from 'react'; @@ -118,23 +118,23 @@ function App() { } ``` -В этом примере проверки строгого режима не будут выполняться для компонентов `Header` и `Footer`. Однако, они будут выполняться для `Sidebar` и `Content`, так же как и для всех компонентов внутри них, независимо от глубины вложенности. +В этом примере проверки строгого режима не будут выполняться для компонентов `Header` и `Footer`. Однако, они будут выполняться для `Sidebar` и `Content`, а также для всех компонентов внутри них, независимо от глубины вложенности. --- ### Исправление багов, найденных повторным рендерингом в режиме разработки {/*fixing-bugs-found-by-double-rendering-in-development*/} -[React предполагает, что каждый компонент является чистой функцией.](/learn/keeping-components-pure) Это значит, что React-компоненты, которые вы пишете, должны всегда возвращать одинаковый JSX при тех же входных данных (пропсах, состоянии и контексте). +[React предполагает, что каждый компонент является чистой функцией.](/learn/keeping-components-pure) Это значит, что React-компоненты, которые вы создаёте, должны всегда возвращать тот же JSX при одинаковых параметрах (пропсах, состоянии и контексте). -Компоненты, которые нарушают это правило, ведут себя непредсказуемо и вызывают ошибки. Чтобы помочь вам найти случайный нечистый код, строгий режим вызывает некоторые ваши функции (только те, которые должны быть чистыми) **дважды в режиме разработки.** Это включает: +Компоненты, которые нарушают это правило, работают непостоянно и приводят к ошибкам. Чтобы помочь вам обнаружить случайно нечистый код, строгий режим запускает некоторые из ваших функций (только те, которые должны быть чистыми) **два раза в режиме разработки.** Это касается: -- Тело компонента (только высокоуровневая логика, без учета кода внутри обработчиков событий) -- Функции, которые передаются в функции или хуки [`useState`](/reference/react/useState), [`set`](/reference/react/useState#setstate), [`useMemo`](/reference/react/useMemo), или [`useReducer`](/reference/react/useReducer) +- Тело функции компонента (только логика верхнего уровня, без учета кода внутри обработчиков событий) +- Функции, которые передаются в функции [`useState`](/reference/react/useState), [`set` функции](/reference/react/useState#setstate), [`useMemo`](/reference/react/useMemo), или [`useReducer`](/reference/react/useReducer) - Некоторые методы классовых компонентов, такие как [`constructor`](/reference/react/Component#constructor), [`render`](/reference/react/Component#render), [`shouldComponentUpdate`](/reference/react/Component#shouldcomponentupdate) ([полный список](https://reactjs.org/docs/strict-mode.html#detecting-unexpected-side-effects)) -Если функция является чистой, то ее двойной вызов не будет менять ее поведение, так как чистая функция выдает один и тот же результат каждый раз. Однако, если функция не является чистой (например, мутирует получаемые данные), ее двойной вызов будет заметным (именно это и делает ее нечистой!). Это поможет вам заметить и поправить баг заранее. +Если функция является чистой, то её повторный запуск не меняет её поведения, потому что чистая функция всегда даёт одинаковый результат. Но если функция является нечистой (например, мутирует получаемые данные), то её повторный запуск обычно заметен (это и делает её нечистой!). Это помогает вам быстрее находить и исправлять баг. -**Вот пример, который иллюстрирует, как повторный рендеринг в строгом режиме помогает вам находить баги на ранней стадии.** +**Вот пример, который показывает, как повторный рендеринг в строгом режиме помогает вам находить баги на ранней стадии.** Компонент `StoryTray` принимает массив `stories` и добавляет в конец этого массива один элемент "Create Story": @@ -212,9 +212,9 @@ li { -В коде выше есть ошибка. Однако ее легко пропустить, так как изначальный вывод выглядит правильным. +В коде выше закралась ошибка. Но её не так просто заметить, потому что на первый взгляд всё выглядит правильно. -Ошибка будет более заметна, если компонент `StoryTray` будет отрендерен несколько раз. Например, давайте сделаем повторный рендеринг компонента `StoryTray` с другим цветом фона, когда наводим мышью: +Ошибка станет более заметной, если компонент `StoryTray` будет отрендерен несколько раз. Например, давайте сделаем так, чтобы `StoryTray` рендерился с другим цветом фона каждый раз, когда вы наводите на него курсор: @@ -299,9 +299,9 @@ li { -Обратите внимание, что каждый раз, когда мы наводим мышь на компонент `StoryTray`, "Create Story" добавляется в массив еще раз. Изначально требовалось добавить его лишь один раз в конец массива, но `StoryTray` напрямую мутирует массив `stories` из пропсов. Каждый раз, когда `StoryTray` рендерится, элемент "Create Story" опять добавляется в конец того же самого массива. Другими словами, `StoryTray` не является чистой функцией--при повторном рендеринге она возвращает разные результаты. +Заметьте, как каждый раз, когда вы наводите курсор мыши на компонент `StoryTray`, "Create Story" снова добавляется в массив еще раз. Целью кода было добавить его лишь один раз в конец. Но `StoryTray` напрямую изменяет массив `stories` из пропсов. Каждый раз, когда `StoryTray` рендерится, элемент "Create Story" снова добавляется в конец того же самого массива. Другими словами, `StoryTray` не является чистой функцией -- её многократный запуск приводит к разным результатам. -Чтобы исправить эту проблему, нужно сделать копию массива и изменять ее, а не оригинальный массив: +Чтобы исправить эту проблему, вы можете создать копию массива и изменять её вместо оригинального массива: ```js {2} export default function StoryTray({ stories }) { @@ -310,7 +310,7 @@ export default function StoryTray({ stories }) { items.push({ id: 'create', label: 'Create Story' }); ``` -Так [компонент `StoryTray` станет чистым.](/learn/keeping-components-pure) Каждый раз, когда он вызывается, он будет только изменять новую копию массива и не будет влиять на внешние объекты или переменные. Это решает проблему, но вам нужно было сделать так, чтобы компонент чаще ре-рендерился, прежде чем стало очевидно, что его поведение некорректное. +Это бы [сделало функцию `StoryTray` чистой.](/learn/keeping-components-pure) Каждый раз, когда она вызывается, она бы только изменяла новую копию массива и не влияла бы на какие-либо внешние объекты или переменные. Это решает проблему, но вам пришлось заставить компонент рендериться чаще, прежде чем стало очевидно, что его поведение некорректное. **В оригинальном примере ошибка не была очевидной. Теперь давайте обернем исходный (с ошибкой) код в ``:** @@ -393,7 +393,7 @@ li { -**Строгий режим *всегда* вызывает рендеринг дважды, чтобы вы могли сразу увидеть ошибку** ("Create Story" появляется дважды). Это позволяет замечать такие ошибки на ранней стадии разработки. Когда вы заставляете ваш компонент рендерится в Strict Mode, вы *также* правите множество потенциальных багов продакшен-сборки, как например функциональность наведения мыши ниже: +**Строгий режим *всегда* вызывает функцию рендеринга дважды, поэтому вы сразу же можете увидеть ошибку** ("Create Story" появляется дважды). Это позволяет замечать такие ошибки на ранней стадии разработки. Когда вы заставляете ваш компонент работать в строгом режиме, вы *также* устраняете множество потенциальных багов в продакшене, таких, как поведение при наведении мыши из предыдущего примера: @@ -442,7 +442,7 @@ import { useState } from 'react'; export default function StoryTray({ stories }) { const [isHover, setIsHover] = useState(false); - const items = stories.slice(); // Clone the array + const items = stories.slice(); // Клонируем массив items.push({ id: 'create', label: 'Create Story' }); return (
              -Без строгого режима было легко пропустить ошибку, пока вы не добавили больше ре-рендеров. Строгий режим сразу показал ошибку. Он помогает вам находить баги перед тем, как вы отправите их вашей команде или пользователям. +Без строгого режима было легко пропустить ошибку, пока вы не добавили больше ре-рендеров. Строгий режим выявил эту ошибку сразу. Строгий режим спасает вас от ошибок, которые могут испортить работу вашей команды и вызывать проблемы у ваших пользователей. -[Как сохранять компоненты чистыми.](/learn/keeping-components-pure) +[Подробнее о том, как сохранять компоненты чистыми.](/learn/keeping-components-pure) -Если у вас установлены [React DevTools](/learn/react-developer-tools), любые вызовы `console.log` во время повторного рендеринга будут выглядеть немного приглушенными. React DevTools также имеет настройку (выключена по умолчанию) для их полного отключения. +Если у вас установлены [React DevTools](/learn/react-developer-tools), любые вызовы `console.log` во время повторного рендеринга будут выглядеть менее ярко. React DevTools также имеет настройку (выключена по умолчанию) для их полного отключения. --- -### Исправление багов, найденных повторным вызовом эффекта в режиме разработки {/*fixing-bugs-found-by-re-running-effects-in-development*/} +### Исправление багов, найденных при повторном запуске эффектов в режиме разработки {/*fixing-bugs-found-by-re-running-effects-in-development*/} -Strict Mode также может помогать находить ошибки в [эффектах.](/learn/synchronizing-with-effects) +Строгий режим также помогает находить ошибки в [эффектах.](/learn/synchronizing-with-effects) -Каждый эффект имеет код установки и может иметь код для сброса эффекта. Обычно React вызывает код установки, когда компонент *монтируется* (добавляется на экран) и вызывает код сброса, когда компонент *размонтируется* (удаляется с экрана). React затем вызывает сбрасывающую и установку заново, если зависимости эффекта были изменены с момента последнего рендера. +Каждый эффект имеет свой код установки и, возможно, код для сброса. Обычно React вызывает код установки, при *монтировании* компонента (его добавлении на экран) и вызывает сброс при *размонтировании* компонента (его удалении с экрана). Если зависимости эффекта изменилис с момента последнего рендера, React вызывает сброс и установку заново. -Когда строгий режим включен, React также вызовет **один дополнительный цикл установки и сброса для каждого эффекта в режиме разработки.** Это может быть неожиданным, но это помогает находить ошибки, которые сложно отловить вручную. +Когда строгий режим включен, React будет запускать **один дополнительный цикл установки и сброса для каждого эффекта в режиме разработки.** Это может быть неожиданным, но это помогает находить баги, которые сложно отловить вручную. -**Вот пример, иллюстрирующий то, как повторный вызов эффектов в строгом режиме помогает вам найти ошибки на ранней стадии.** +**Вот пример, иллюстрирующий то, как повторный запуск эффектов в строгом режиме помогает вам находить баги на ранней стадии.** -Рассмотрим пример, который подключает компонент к чату: +Рассмотрим пример, в котором компонент подключается к чату: @@ -539,17 +539,17 @@ export default function ChatRoom() { let connections = 0; export function createConnection(serverUrl, roomId) { - // A real implementation would actually connect to the server + // Настоящий код, который действительно подключается к серверу return { connect() { - console.log('✅ Connecting to "' + roomId + '" room at ' + serverUrl + '...'); + console.log('✅ Подключение к комнате "' + roomId + '" по адресу ' + serverUrl + '...'); connections++; - console.log('Active connections: ' + connections); + console.log('Активных подключений: ' + connections); }, disconnect() { - console.log('❌ Disconnected from "' + roomId + '" room at ' + serverUrl); + console.log('❌ Отключение от комнаты "' + roomId + '" по адресу ' + serverUrl); connections--; - console.log('Active connections: ' + connections); + console.log('Активных подключений: ' + connections); } }; } @@ -562,9 +562,9 @@ button { margin-left: 10px; } -В коде допущена ошибка, но это может быть неочевидно. +В коде есть проблема, но, возможно, это не сразу очевидно. -Чтобы сделать проблему более явной, давайте добавим новую функциональность. В примере ниже, `roomId` не указана хардкодом. Вместо этого пользователь может выбрать `roomId`, к которому он хочет подключиться через выпадающее меню. Нажмите на "Open chat" и выберите разные чат-комнаты одну за одной. Обратите внимание на количество активных подключений в консоли: +Для того чтобы проблема стала более очевидной, давайте добавим новую функциональность. В примере ниже, `roomId` не зашит в коде, а пользователь может выбрать `roomId`, к которому он хочет подключиться, из выпадающего списка. Нажмите на "Open chat" и выберите разные чаты один за другим. Следите за количеством активных подключений в консоли: @@ -623,19 +623,19 @@ export default function App() { let connections = 0; export function createConnection(serverUrl, roomId) { - // A real implementation would actually connect to the server - return { - connect() { - console.log('✅ Connecting to "' + roomId + '" room at ' + serverUrl + '...'); - connections++; - console.log('Active connections: ' + connections); - }, - disconnect() { - console.log('❌ Disconnected from "' + roomId + '" room at ' + serverUrl); - connections--; - console.log('Active connections: ' + connections); - } - }; + // Настоящий код, который действительно подключается к серверу + return { + connect() { + console.log('✅ Подключение к комнате "' + roomId + '" по адресу ' + serverUrl + '...'); + connections++; + console.log('Активных подключений: ' + connections); + }, + disconnect() { + console.log('❌ Отключение от комнаты "' + roomId + '" по адресу ' + serverUrl); + connections--; + console.log('Активных подключений: ' + connections); + } + }; } ``` @@ -646,7 +646,7 @@ button { margin-left: 10px; } -Вы заметите, что число открытых подключений постоянно возрастает. В настоящем приложении это может вызывать проблемы с сетью и производительностью. Корень проблемы в том, что [в эффекте отсутствует сбрасывающая функция:](/learn/synchronizing-with-effects#step-3-add-cleanup-if-needed) +Вы заметите, что число открытых подключений продолжает расти. В реальном приложении это может вызывать проблемы с сетью и производительностью. Проблема заключается в том, что [ваш эффект не содержит функцию сброса:](/learn/synchronizing-with-effects#step-3-add-cleanup-if-needed) ```js {4} useEffect(() => { @@ -656,9 +656,9 @@ button { margin-left: 10px; } }, [roomId]); ``` -Теперь, когда ваш эффект "очищается" и удаляет ненужные подключения, утечка устранена. Обратите внимание, что проблема не стала явной, пока вы не добавили больше функциональности (выпадающее меню). +Теперь, когда ваш эффект "сбрасывается" и удаляет устаревшие подключения, утечка устранена. Обратите внимание, что проблема не стала заметной, пока вы не добавили больше функциональности (выпадающий список). -**В исходном примере ошибка не была очевидной. Теперь давайте обернем исходный код (с ошибкой) в ``:** +**В исходном примере баг не был очевидным. Теперь давайте обернём исходный код (с багом) в ``:** @@ -697,19 +697,19 @@ export default function ChatRoom() { let connections = 0; export function createConnection(serverUrl, roomId) { - // A real implementation would actually connect to the server - return { - connect() { - console.log('✅ Connecting to "' + roomId + '" room at ' + serverUrl + '...'); - connections++; - console.log('Active connections: ' + connections); - }, - disconnect() { - console.log('❌ Disconnected from "' + roomId + '" room at ' + serverUrl); - connections--; - console.log('Active connections: ' + connections); - } - }; + // Настоящий код, который действительно подключается к серверу + return { + connect() { + console.log('✅ Подключение к комнате "' + roomId + '" по адресу ' + serverUrl + '...'); + connections++; + console.log('Активных подключений: ' + connections); + }, + disconnect() { + console.log('❌ Отключение от комнаты "' + roomId + '" по адресу ' + serverUrl); + connections--; + console.log('Активных подключений: ' + connections); + } + }; } ``` @@ -720,9 +720,9 @@ button { margin-left: 10px; } -**Благодаря строгому режиму вы сразу видите, что есть проблема** (количество активных подключений возрастает до 2). Строгий режим вызывает дополнительный цикл установки и сброса для каждого эффекта. У этого эффекта отсутствует логика сброса, поэтому он создает дополнительное подключение и не удаляет его. Это подсказка, что в эффекте отсутствует сбрасывающая функция. +**Благодаря строгому режиму вы сразу видите проблему** (количество активных подключений увеличивается до 2). Строгий режим запускает дополнительный цикл установки и сброса для каждого эффекта. У этого эффекта отсутствует логика сброса, поэтому он создаёт дополнительное подключение и не удаляет его. Это подсказка, что в эффекте отсутствует функция сброса. -Строгий режим позволяет вам замечать подобные ошибки на ранней стадии разработки. Когда вы поправите ваш эффект, добавив сбрасывающую функцию в строгом режиме, вы *также* поправите множество потенциальных багов продакшена, например, как выпадающее меню, которое мы рассматривали ранее: +Строгий режим позволяет вам заметить подобные ошибки на ранней стадии разработки. Когда вы поправите ваш эффект, добавляя сбрасывающую функцию сброса в строгом режиме, вы *также* поправите множество потенциальных багов продакшена, например, как с выпадающим списком, который мы рассматривали ранее: @@ -787,19 +787,19 @@ export default function App() { let connections = 0; export function createConnection(serverUrl, roomId) { - // A real implementation would actually connect to the server - return { - connect() { - console.log('✅ Connecting to "' + roomId + '" room at ' + serverUrl + '...'); - connections++; - console.log('Active connections: ' + connections); - }, - disconnect() { - console.log('❌ Disconnected from "' + roomId + '" room at ' + serverUrl); - connections--; - console.log('Active connections: ' + connections); - } - }; + // Настоящий код, который действительно подключается к серверу + return { + connect() { + console.log('✅ Подключение к комнате "' + roomId + '" по адресу ' + serverUrl + '...'); + connections++; + console.log('Активных подключений: ' + connections); + }, + disconnect() { + console.log('❌ Отключение от комнаты "' + roomId + '" по адресу ' + serverUrl); + connections--; + console.log('Активных подключений: ' + connections); + } + }; } ``` @@ -810,21 +810,21 @@ button { margin-left: 10px; } -Обратите внимание, как количество активных подключений в консоли больше не растет. +Обратите внимание, что количество активных подключений в консоли больше не растёт. -Без строгого режима было легко пропустить, что у вашего эффекта отсутствует сбрасывающая функция. Благодаря вызову *установки → сброса → установки* вместо *установки* для вашего эффекта в режиме разработки, строгий режим сделал отсутствие сбрасывающей функции более заметной. +Без строгого режима было легко пропустить, что у вашего эффекта отсутствует функция сброса. Благодаря вызову *установка → сброс → установка* вместо *установка* для вашего эффекта в режиме разработки, строгий режим сделал отсутствие функции сброса более заметным. -[Узнать больше о сбрасывающей функции в эффекте.](/learn/synchronizing-with-effects#how-to-handle-the-effect-firing-twice-in-development) +[Узнать больше о функции сброса эффекта.](/learn/synchronizing-with-effects#how-to-handle-the-effect-firing-twice-in-development) --- ### Исправление предупреждений об устаревших методах в строгом режиме {/*fixing-deprecation-warnings-enabled-by-strict-mode*/} -React предупреждает, если какой-либо компонент внутри дерева `` использует какое-либо из следующих устаревших API: +React предупреждает, если какой-либо компонент внутри дерева `` использует одно из следующих устаревших API: * [`findDOMNode`](/reference/react-dom/findDOMNode). [Смотреть альтернативные решения.](https://reactjs.org/docs/strict-mode.html#warning-about-deprecated-finddomnode-usage) * `UNSAFE_` классовые методы жизненного цикла, такие как [`UNSAFE_componentWillMount`](/reference/react/Component#unsafe_componentwillmount). [Смотреть альтернативные решения.](https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html#migrating-from-legacy-lifecycles) -* Устаревший контекст ([`childContextTypes`](/reference/react/Component#static-childcontexttypes), [`contextTypes`](/reference/react/Component#static-contexttypes), и[`getChildContext`](/reference/react/Component#getchildcontext)). [Смотреть альтернативные решения.](/reference/react/createContext) +* Устаревший контекст ([`childContextTypes`](/reference/react/Component#static-childcontexttypes), [`contextTypes`](/reference/react/Component#static-contexttypes), и [`getChildContext`](/reference/react/Component#getchildcontext)). [Смотреть альтернативные решения.](/reference/react/createContext) * Устаревшие строковые рефы ([`this.refs`](/reference/react/Component#refs)). [Смотреть альтернативные решения.](https://reactjs.org/docs/strict-mode.html#warning-about-legacy-string-ref-api-usage) Эти API в основном используются в старых [классовых компонентах](/reference/react/Component), поэтому они редко встречаются в современных приложениях. From 01153b5bc41e8f00ccf622858249b7c4d9aec580 Mon Sep 17 00:00:00 2001 From: Jana Korichneva Date: Sat, 13 May 2023 13:20:08 +0400 Subject: [PATCH 136/233] fix code formatting --- src/content/reference/react/StrictMode.md | 78 +++++++++++------------ 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/src/content/reference/react/StrictMode.md b/src/content/reference/react/StrictMode.md index bdfa1ec9a..545e55617 100644 --- a/src/content/reference/react/StrictMode.md +++ b/src/content/reference/react/StrictMode.md @@ -623,19 +623,19 @@ export default function App() { let connections = 0; export function createConnection(serverUrl, roomId) { - // Настоящий код, который действительно подключается к серверу - return { - connect() { - console.log('✅ Подключение к комнате "' + roomId + '" по адресу ' + serverUrl + '...'); - connections++; - console.log('Активных подключений: ' + connections); - }, - disconnect() { - console.log('❌ Отключение от комнаты "' + roomId + '" по адресу ' + serverUrl); - connections--; - console.log('Активных подключений: ' + connections); - } - }; + // Настоящий код, который действительно подключается к серверу + return { + connect() { + console.log('✅ Подключение к комнате "' + roomId + '" по адресу ' + serverUrl + '...'); + connections++; + console.log('Активных подключений: ' + connections); + }, + disconnect() { + console.log('❌ Отключение от комнаты "' + roomId + '" по адресу ' + serverUrl); + connections--; + console.log('Активных подключений: ' + connections); + } + }; } ``` @@ -697,19 +697,19 @@ export default function ChatRoom() { let connections = 0; export function createConnection(serverUrl, roomId) { - // Настоящий код, который действительно подключается к серверу - return { - connect() { - console.log('✅ Подключение к комнате "' + roomId + '" по адресу ' + serverUrl + '...'); - connections++; - console.log('Активных подключений: ' + connections); - }, - disconnect() { - console.log('❌ Отключение от комнаты "' + roomId + '" по адресу ' + serverUrl); - connections--; - console.log('Активных подключений: ' + connections); - } - }; + // Настоящий код, который действительно подключается к серверу + return { + connect() { + console.log('✅ Подключение к комнате "' + roomId + '" по адресу ' + serverUrl + '...'); + connections++; + console.log('Активных подключений: ' + connections); + }, + disconnect() { + console.log('❌ Отключение от комнаты "' + roomId + '" по адресу ' + serverUrl); + connections--; + console.log('Активных подключений: ' + connections); + } + }; } ``` @@ -787,19 +787,19 @@ export default function App() { let connections = 0; export function createConnection(serverUrl, roomId) { - // Настоящий код, который действительно подключается к серверу - return { - connect() { - console.log('✅ Подключение к комнате "' + roomId + '" по адресу ' + serverUrl + '...'); - connections++; - console.log('Активных подключений: ' + connections); - }, - disconnect() { - console.log('❌ Отключение от комнаты "' + roomId + '" по адресу ' + serverUrl); - connections--; - console.log('Активных подключений: ' + connections); - } - }; + // Настоящий код, который действительно подключается к серверу + return { + connect() { + console.log('✅ Подключение к комнате "' + roomId + '" по адресу ' + serverUrl + '...'); + connections++; + console.log('Активных подключений: ' + connections); + }, + disconnect() { + console.log('❌ Отключение от комнаты "' + roomId + '" по адресу ' + serverUrl); + connections--; + console.log('Активных подключений: ' + connections); + } + }; } ``` From e7f71ffbf51a7b5d23f310356b5ccf1486e167b8 Mon Sep 17 00:00:00 2001 From: TibidoX <79273248+TibidoX@users.noreply.github.com> Date: Mon, 15 May 2023 15:07:38 +0300 Subject: [PATCH 137/233] Translation renderToString.md --- .../react-dom/server/renderToString.md | 74 +++++++++---------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/src/content/reference/react-dom/server/renderToString.md b/src/content/reference/react-dom/server/renderToString.md index 41bc6a982..d3cc51b92 100644 --- a/src/content/reference/react-dom/server/renderToString.md +++ b/src/content/reference/react-dom/server/renderToString.md @@ -1,16 +1,16 @@ --- -title: renderToString +Заголовок: renderToString --- -`renderToString` does not support streaming or waiting for data. [See the alternatives.](#alternatives) +`renderToString` не поддерживает потоковую передачу или ожидание данных. [Смотрите альтернативные варианты.](#alternatives) -`renderToString` renders a React tree to an HTML string. +`renderToString` рендерит дерево React в HTML-строку. ```js const html = renderToString(reactNode) @@ -22,11 +22,11 @@ const html = renderToString(reactNode) --- -## Reference {/*reference*/} +## Справка {/*reference*/} ### `renderToString(reactNode)` {/*rendertostring*/} -On the server, call `renderToString` to render your app to HTML. +На сервере вызовите `renderToString`, чтобы отрендерить ваше приложение в HTML. ```js import { renderToString } from 'react-dom/server'; @@ -34,81 +34,81 @@ import { renderToString } from 'react-dom/server'; const html = renderToString(); ``` -On the client, call [`hydrateRoot`](/reference/react-dom/client/hydrateRoot) to make the server-generated HTML interactive. +На клиенте вызовите [`hydrateRoot`](/reference/react-dom/client/hydrateRoot), чтобы сделать интерактивным HTML, который сгенерировал сервер. -[See more examples below.](#usage) +[Смотрите больше примеров ниже.](#usage) -#### Parameters {/*parameters*/} +#### Параметры {/*parameters*/} -* `reactNode`: A React node you want to render to HTML. For example, a JSX node like ``. +* `reactNode`: Узел React, который вы хотите отрендерить в HTML. Например, JSX узел типа ``. -#### Returns {/*returns*/} +#### Возвращаемые значения {/*returns*/} -An HTML string. +Строка HTML. -#### Caveats {/*caveats*/} +#### Предостережения {/*caveats*/} -* `renderToString` has limited Suspense support. If a component suspends, `renderToString` immediately sends its fallback as HTML. +* `renderToString` имеет ограниченную поддержку задержки. Если компонент приостановлен, `renderToString` немедленно отправляет его резервный вариант в виде HTML. -* `renderToString` works in the browser, but using it in the client code is [not recommended.](#removing-rendertostring-from-the-client-code) +* `renderToString` работает в браузере, но использовать его в клиентском коде [не рекомендуется.](#removing-rendertostring-from-the-client-code) --- -## Usage {/*usage*/} +## Применение {/*usage*/} -### Rendering a React tree as HTML to a string {/*rendering-a-react-tree-as-html-to-a-string*/} +### Рендеринг дерева React как строки HTML {/*rendering-a-react-tree-as-html-to-a-string*/} -Call `renderToString` to render your app to an HTML string which you can send with your server response: +Вызовите `renderToString`, чтобы отрендерить ваше приложение в строку HTML, которую вы можете отправить вместе с ответом вашего сервера: ```js {5-6} import { renderToString } from 'react-dom/server'; -// The route handler syntax depends on your backend framework +// Синтаксис обработчика маршрута зависит от вашего бэкенд-фреймворка app.use('/', (request, response) => { const html = renderToString(); response.send(html); }); ``` -This will produce the initial non-interactive HTML output of your React components. On the client, you will need to call [`hydrateRoot`](/reference/react-dom/client/hydrateRoot) to *hydrate* that server-generated HTML and make it interactive. +Этот код создает исходный неинтерактивный HTML-вывод ваших компонентов React. На клиенте вам нужно будет вызвать [`hydrateRoot`](/reference/react-dom/client/hydrateRoot), чтобы сделать HTML, который сгенерировал сервер, интерактивным. -`renderToString` does not support streaming or waiting for data. [See the alternatives.](#alternatives) +`renderToString` не поддерживает потоковую передачу или ожидание данных. [Смотрите альтернативные варианты.](#alternatives) --- -## Alternatives {/*alternatives*/} +## Альтернативные варианты {/*alternatives*/} -### Migrating from `renderToString` to a streaming method on the server {/*migrating-from-rendertostring-to-a-streaming-method-on-the-server*/} +### Переход от `renderToString` к потоковому методу на сервере {/*migrating-from-rendertostring-to-a-streaming-method-on-the-server*/} -`renderToString` returns a string immediately, so it does not support streaming or waiting for data. +`renderToString` немедленно возвращает строку, поэтому он не поддерживает потоковую передачу или ожидание данных. -When possible, we recommend using these fully-featured alternatives: +Мы рекомендуем использовать эти полнофункциональные альтернативы, когда это возможно: -* If you use Node.js, use [`renderToPipeableStream`.](/reference/react-dom/server/renderToPipeableStream) -* If you use Deno or a modern edge runtime with [Web Streams](https://developer.mozilla.org/en-US/docs/Web/API/Streams_API), use [`renderToReadableStream`.](/reference/react-dom/server/renderToReadableStream) +* Если вы используете Node.js, используйте [`renderToPipeableStream`.](/reference/react-dom/server/renderToPipeableStream) +* Если вы используете Deno или современную пограничную среду выполнения с [Web Streams](https://developer.mozilla.org/en-US/docs/Web/API/Streams_API), используйте [`renderToReadableStream`.](/reference/react-dom/server/renderToReadableStream) -You can continue using `renderToString` if your server environment does not support streams. +Вы можете продолжать использовать`renderToString`, если среда вашего сервера не поддерживает потоки. --- -### Removing `renderToString` from the client code {/*removing-rendertostring-from-the-client-code*/} +### Удаление `renderToString` из клиентского кода {/*removing-rendertostring-from-the-client-code*/} -Sometimes, `renderToString` is used on the client to convert some component to HTML. +Иногда `renderToString` используют на клиенте для преобразования какого-либо компонента в HTML. ```js {1-2} -// 🚩 Unnecessary: using renderToString on the client +// 🚩 Лишнее: использование renderToString на клиенте import { renderToString } from 'react-dom/server'; const html = renderToString(); console.log(html); // For example, "..." ``` -Importing `react-dom/server` **on the client** unnecessarily increases your bundle size and should be avoided. If you need to render some component to HTML in the browser, use [`createRoot`](/reference/react-dom/client/createRoot) and read HTML from the DOM: +Импорт `react-dom/server` **на клиенте** излишне увеличивает размер пакета, и этого следует избегать. Если вам в браузере нужно преобразовать какой-либо компонент в HTML, используйте [`createRoot`](/reference/react-dom/client/createRoot) и читайте HTML из DOM: ```js import { createRoot } from 'react-dom/client'; @@ -122,17 +122,17 @@ flushSync(() => { console.log(div.innerHTML); // For example, "..." ``` -The [`flushSync`](/reference/react-dom/flushSync) call is necessary so that the DOM is updated before reading its [`innerHTML`](https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML) property. +Вызов [`flushSync`](/reference/react-dom/flushSync) необходим, чтобы DOM обновлялся перед чтением его свойства [`innerHTML`](https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML). --- -## Troubleshooting {/*troubleshooting*/} +## Поиск неисправностей {/*troubleshooting*/} -### When a component suspends, the HTML always contains a fallback {/*when-a-component-suspends-the-html-always-contains-a-fallback*/} +### Когда компонент приостанавливается, HTML всегда содержит запасной вариант {/*when-a-component-suspends-the-html-always-contains-a-fallback*/} -`renderToString` does not fully support Suspense. +`renderToString` не полностью поддерживает задержку. -If some component suspends (for example, because it's defined with [`lazy`](/reference/react/lazy) or fetches data), `renderToString` will not wait for its content to resolve. Instead, `renderToString` will find the closest [``](/reference/react/Suspense) boundary above it and render its `fallback` prop in the HTML. The content will not appear until the client code loads. +Если какой-либо компонент приостанавливается (например, потому что он определен с [`lazy`](/reference/react/lazy) или извлекает данные), `renderToString` не будет ждать разрешения своего содержимого. Вместо этого `renderToString` найдет ближайшую [``](/reference/react/Suspense) границу над ней и отрендерит её `резервный вариант` в HTML. Содержимое не появится, пока не загрузится клиентский код. -To solve this, use one of the [recommended streaming solutions.](#migrating-from-rendertostring-to-a-streaming-method-on-the-server) They can stream content in chunks as it resolves on the server so that the user sees the page being progressively filled in before the client code loads. +Чтобы решить эту проблему, используйте одно из [рекомендуемых решений для потоковой передачи.](#migrating-from-rendertostring-to-a-streaming-method-on-the-server) Они могут передавать контент фрагментами по мере его разрешения на сервере, чтобы пользователь видел, что страница постепенно заполняется до загрузки клиентского кода. From 73a68e2ec8eb487a53eeb0660f457d4ebcbe06b2 Mon Sep 17 00:00:00 2001 From: TibidoX <79273248+TibidoX@users.noreply.github.com> Date: Mon, 15 May 2023 15:11:52 +0300 Subject: [PATCH 138/233] Translate renderToString.md --- src/content/reference/react-dom/server/renderToString.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/reference/react-dom/server/renderToString.md b/src/content/reference/react-dom/server/renderToString.md index d3cc51b92..9d96d5517 100644 --- a/src/content/reference/react-dom/server/renderToString.md +++ b/src/content/reference/react-dom/server/renderToString.md @@ -105,7 +105,7 @@ app.use('/', (request, response) => { import { renderToString } from 'react-dom/server'; const html = renderToString(); -console.log(html); // For example, "..." +console.log(html); // Например, "..." ``` Импорт `react-dom/server` **на клиенте** излишне увеличивает размер пакета, и этого следует избегать. Если вам в браузере нужно преобразовать какой-либо компонент в HTML, используйте [`createRoot`](/reference/react-dom/client/createRoot) и читайте HTML из DOM: From 24ecaf30d162dc02efcf08b4d27d8ad5279c8e30 Mon Sep 17 00:00:00 2001 From: TibidoX <79273248+TibidoX@users.noreply.github.com> Date: Mon, 15 May 2023 15:15:16 +0300 Subject: [PATCH 139/233] Translate renderToString.md --- src/content/reference/react-dom/server/renderToString.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/content/reference/react-dom/server/renderToString.md b/src/content/reference/react-dom/server/renderToString.md index 9d96d5517..c332a03c3 100644 --- a/src/content/reference/react-dom/server/renderToString.md +++ b/src/content/reference/react-dom/server/renderToString.md @@ -48,7 +48,7 @@ const html = renderToString(); #### Предостережения {/*caveats*/} -* `renderToString` имеет ограниченную поддержку задержки. Если компонент приостановлен, `renderToString` немедленно отправляет его резервный вариант в виде HTML. +* `renderToString` имеет ограниченную поддержку задержки. Если компонент приостановлен, `renderToString` немедленно отправляет fallback в виде HTML. * `renderToString` работает в браузере, но использовать его в клиентском коде [не рекомендуется.](#removing-rendertostring-from-the-client-code) @@ -128,11 +128,11 @@ console.log(div.innerHTML); // For example, "..." ## Поиск неисправностей {/*troubleshooting*/} -### Когда компонент приостанавливается, HTML всегда содержит запасной вариант {/*when-a-component-suspends-the-html-always-contains-a-fallback*/} +### Когда компонент приостанавливается, HTML всегда содержит fallback {/*when-a-component-suspends-the-html-always-contains-a-fallback*/} `renderToString` не полностью поддерживает задержку. -Если какой-либо компонент приостанавливается (например, потому что он определен с [`lazy`](/reference/react/lazy) или извлекает данные), `renderToString` не будет ждать разрешения своего содержимого. Вместо этого `renderToString` найдет ближайшую [``](/reference/react/Suspense) границу над ней и отрендерит её `резервный вариант` в HTML. Содержимое не появится, пока не загрузится клиентский код. +Если какой-либо компонент приостанавливается (например, потому что он определен с [`lazy`](/reference/react/lazy) или извлекает данные), `renderToString` не будет ждать разрешения своего содержимого. Вместо этого `renderToString` найдет ближайшую [``](/reference/react/Suspense) границу над ней и отрендерит её `fallback` в HTML. Содержимое не появится, пока не загрузится клиентский код. Чтобы решить эту проблему, используйте одно из [рекомендуемых решений для потоковой передачи.](#migrating-from-rendertostring-to-a-streaming-method-on-the-server) Они могут передавать контент фрагментами по мере его разрешения на сервере, чтобы пользователь видел, что страница постепенно заполняется до загрузки клиентского кода. From cea64ff62f4586724606dd61e3ba641e1b49b20e Mon Sep 17 00:00:00 2001 From: TibidoX <79273248+TibidoX@users.noreply.github.com> Date: Mon, 15 May 2023 15:16:12 +0300 Subject: [PATCH 140/233] Translate renderToString.md --- src/content/reference/react-dom/server/renderToString.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/reference/react-dom/server/renderToString.md b/src/content/reference/react-dom/server/renderToString.md index c332a03c3..c52f85d3c 100644 --- a/src/content/reference/react-dom/server/renderToString.md +++ b/src/content/reference/react-dom/server/renderToString.md @@ -119,7 +119,7 @@ const root = createRoot(div); flushSync(() => { root.render(); }); -console.log(div.innerHTML); // For example, "..." +console.log(div.innerHTML); // Например, "..." ``` Вызов [`flushSync`](/reference/react-dom/flushSync) необходим, чтобы DOM обновлялся перед чтением его свойства [`innerHTML`](https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML). From 2a769184345a8a9bb4a18442b413828a7adb6ae3 Mon Sep 17 00:00:00 2001 From: TibidoX <79273248+TibidoX@users.noreply.github.com> Date: Mon, 15 May 2023 15:33:55 +0300 Subject: [PATCH 141/233] change link --- src/content/reference/react-dom/server/renderToString.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/reference/react-dom/server/renderToString.md b/src/content/reference/react-dom/server/renderToString.md index c52f85d3c..cd3187900 100644 --- a/src/content/reference/react-dom/server/renderToString.md +++ b/src/content/reference/react-dom/server/renderToString.md @@ -122,7 +122,7 @@ flushSync(() => { console.log(div.innerHTML); // Например, "..." ``` -Вызов [`flushSync`](/reference/react-dom/flushSync) необходим, чтобы DOM обновлялся перед чтением его свойства [`innerHTML`](https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML). +Вызов [`flushSync`](/reference/react-dom/flushSync) необходим, чтобы DOM обновлялся перед чтением его свойства [`innerHTML`](https://developer.mozilla.org/ru/docs/Web/API/Element/innerHTML). --- From fd8ba03f4d7222ac4813374843a44755fc8c64c4 Mon Sep 17 00:00:00 2001 From: Choi siun Date: Wed, 17 May 2023 03:01:40 +0900 Subject: [PATCH 142/233] docs(types): Fix incorrect period positioning in common.md (#6040) --- src/content/reference/react-dom/components/common.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/reference/react-dom/components/common.md b/src/content/reference/react-dom/components/common.md index ca16b6a6e..b8b80ea2f 100644 --- a/src/content/reference/react-dom/components/common.md +++ b/src/content/reference/react-dom/components/common.md @@ -156,7 +156,7 @@ nt. * [`title`](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/title): A string. Specifies the tooltip text for the element. * [`translate`](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/translate): Either `'yes'` or `'no'`. Passing `'no'` excludes the element content from being translated. -You can also pass custom attributes as props, for example `mycustomprop="someValue".` This can be useful when integrating with third-party libraries. The custom attribute name must be lowercase and must not start with `on`. The value will be converted to a string. If you pass `null` or `undefined`, the custom attribute will be removed. +You can also pass custom attributes as props, for example `mycustomprop="someValue"`. This can be useful when integrating with third-party libraries. The custom attribute name must be lowercase and must not start with `on`. The value will be converted to a string. If you pass `null` or `undefined`, the custom attribute will be removed. These events fire only for the [`
              `](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form) elements: From bea2ff778d489eb0401eef173a3b7bf74563930e Mon Sep 17 00:00:00 2001 From: vicsantizo <68677648+vicsantizo@users.noreply.github.com> Date: Tue, 16 May 2023 12:01:59 -0600 Subject: [PATCH 143/233] fix(typos): replace word "ever" with "every" (#6039) --- src/content/reference/react-dom/components/common.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/reference/react-dom/components/common.md b/src/content/reference/react-dom/components/common.md index b8b80ea2f..f1e4fcd0c 100644 --- a/src/content/reference/react-dom/components/common.md +++ b/src/content/reference/react-dom/components/common.md @@ -260,7 +260,7 @@ React will also call your `ref` callback whenever you pass a *different* `ref` c #### Parameters {/*ref-callback-parameters*/} -* `node`: A DOM node or `null`. React will pass you the DOM node when the ref gets attached, and `null` when the ref gets detached. Unless you pass the same function reference for the `ref` callback on every render, the callback will get temporarily detached and re-attached during ever re-render of the component. +* `node`: A DOM node or `null`. React will pass you the DOM node when the ref gets attached, and `null` when the ref gets detached. Unless you pass the same function reference for the `ref` callback on every render, the callback will get temporarily detached and re-attached during every re-render of the component. #### Returns {/*returns*/} From 507f0a179d2fd0f0e708c232d580ae90114a65f7 Mon Sep 17 00:00:00 2001 From: jewhyena Date: Wed, 17 May 2023 09:30:09 +0300 Subject: [PATCH 144/233] edit intro text --- src/content/reference/react/useMemo.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/reference/react/useMemo.md b/src/content/reference/react/useMemo.md index 64ab4c7bc..fe2b2a63a 100644 --- a/src/content/reference/react/useMemo.md +++ b/src/content/reference/react/useMemo.md @@ -4,7 +4,7 @@ title: useMemo -Хук `useMemo` позволяет кешировать результаты вычислений между ререндерами. +`useMemo` – хук в React, позволяющий кешировать результаты вычислений между ререндерами. ```js const cachedValue = useMemo(calculateValue, dependencies) From 5bc25d3c36b6e67cd2d86a1145daf6dfa21d4f40 Mon Sep 17 00:00:00 2001 From: Kathryn Middleton Date: Thu, 18 May 2023 12:48:40 -0400 Subject: [PATCH 145/233] Add accessibility note to interactivity section in the new React docs (#6026) * Add accessibility note to interactivity section in the new React docs * Add a11y note to Responding to Events section * Update responding-to-events.md --------- Co-authored-by: dan --- src/content/learn/responding-to-events.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/content/learn/responding-to-events.md b/src/content/learn/responding-to-events.md index 782b6c0f1..4450c4613 100644 --- a/src/content/learn/responding-to-events.md +++ b/src/content/learn/responding-to-events.md @@ -313,6 +313,12 @@ button { margin-right: 10px; } Notice how the `App` component does not need to know *what* `Toolbar` will do with `onPlayMovie` or `onUploadImage`. That's an implementation detail of the `Toolbar`. Here, `Toolbar` passes them down as `onClick` handlers to its `Button`s, but it could later also trigger them on a keyboard shortcut. Naming props after app-specific interactions like `onPlayMovie` gives you the flexibility to change how they're used later. + + + +Make sure that you use the appropriate HTML tags for your event handlers. For example, to handle clicks, use [` ); } diff --git a/src/components/MDX/Sandpack/OpenInCodeSandboxButton.tsx b/src/components/MDX/Sandpack/OpenInCodeSandboxButton.tsx index 18047edb9..42a2d2743 100644 --- a/src/components/MDX/Sandpack/OpenInCodeSandboxButton.tsx +++ b/src/components/MDX/Sandpack/OpenInCodeSandboxButton.tsx @@ -9,13 +9,13 @@ export const OpenInCodeSandboxButton = () => { return ( + title="Open in CodeSandbox"> - Форкнуть + Fork ); }; diff --git a/src/components/MDX/Sandpack/ResetButton.tsx b/src/components/MDX/Sandpack/ResetButton.tsx index dbf9becf0..1ac413138 100644 --- a/src/components/MDX/Sandpack/ResetButton.tsx +++ b/src/components/MDX/Sandpack/ResetButton.tsx @@ -13,9 +13,9 @@ export function ResetButton({onReset}: ResetButtonProps) { ); } diff --git a/src/components/MDX/TerminalBlock.tsx b/src/components/MDX/TerminalBlock.tsx index 3a692f5d4..9fb5ff35f 100644 --- a/src/components/MDX/TerminalBlock.tsx +++ b/src/components/MDX/TerminalBlock.tsx @@ -65,7 +65,7 @@ function TerminalBlock({level = 'info', children}: TerminalBlockProps) { setCopied(true); }}> {' '} - {copied ? 'Скопировано' : 'Скопировать'} + {copied ? 'Copied' : 'Copy'}
            diff --git a/src/content/learn/installation.md b/src/content/learn/installation.md index 6c8fca184..47e628a5b 100644 --- a/src/content/learn/installation.md +++ b/src/content/learn/installation.md @@ -4,7 +4,7 @@ title: Установка -React был спроектирован так, чтобы его можно было внедрять постепенно. Вы можете начать с малого и использовать только ту функциональность React, которая необходима вам в данный момент. Информация в этом разделе будет полезна как при первом знакомстве с React, так и при создании простой динамической HTML-страницы или проектировании сложного React-приложения. +React был спроектирован с самого начала с учётом постепенного внедрения. Вы можете начать с малого и использовать только ту функциональность React, которая необходима вам в данный момент. Информация в этом разделе будет полезна как при первом знакомстве с React, так и при создании простой динамической HTML-страницы или проектировании сложного React-приложения. @@ -41,7 +41,7 @@ export default function App() { ### Поиграть с React локально {/*try-react-locally*/} -Что бы поиграть с React локально на вашем компьютере, [скачайте эту HTML страницу.](https://gist.githubusercontent.com/gaearon/0275b1e1518599bbeafcde4722e79ed1/raw/db72dcbf3384ee1708c4a07d3be79860db04bff0/example.html) Откройте ее в своем текстовом редакторе и браузере! +Что бы поиграть с React локально на вашем компьютере, [скачайте эту HTML страницу.](https://gist.githubusercontent.com/gaearon/0275b1e1518599bbeafcde4722e79ed1/raw/db72dcbf3384ee1708c4a07d3be79860db04bff0/example.html) Откройте её в своем текстовом редакторе и браузере! ## Начать новый React-проект {/*start-a-new-react-project*/} @@ -53,5 +53,5 @@ export default function App() { ## Дальнейшие шаги {/*next-steps*/} -Перейдите к [Введению в React](/learn) для ознакомления с самыми важными его концепциями. +Перейдите к [Введению в React](/learn) для ознакомления с самыми важными его концепциями, с которыми вы будете сталкиваться каждый день. From 1b5e8861ab40d94e030bff0100708106c4689603 Mon Sep 17 00:00:00 2001 From: Sophie Alpert Date: Fri, 19 May 2023 09:44:58 -0700 Subject: [PATCH 148/233] Upgrade React and Next (#6011) * Upgrade React and Next * Fix bug in useNestedScrollLock I guess refs get disconnected before passive effect cleanup runs. useLayoutEffect would also fix it but maybe this is better. --- .github/workflows/analyze.yml | 2 +- .github/workflows/site_lint.yml | 6 +- next.config.js | 4 +- package.json | 8 +- patches/next+12.3.2-canary.7.patch | 22 -- patches/next+13.4.1.patch | 22 ++ src/components/Breadcrumbs.tsx | 8 +- src/components/ButtonLink.tsx | 13 +- src/components/DocsFooter.tsx | 35 ++- src/components/Layout/Footer.tsx | 4 +- src/components/Layout/HomeContent.js | 5 +- src/components/Layout/Sidebar/SidebarLink.tsx | 69 +++--- src/components/Layout/TopNav/TopNav.tsx | 37 +-- src/components/MDX/BlogCard.tsx | 106 ++++---- src/components/MDX/Link.tsx | 9 +- .../MDX/Sandpack/DownloadButton.tsx | 23 +- src/components/Search.tsx | 6 +- yarn.lock | 226 +++++++++--------- 18 files changed, 300 insertions(+), 305 deletions(-) delete mode 100644 patches/next+12.3.2-canary.7.patch create mode 100644 patches/next+13.4.1.patch diff --git a/.github/workflows/analyze.yml b/.github/workflows/analyze.yml index 07271cef6..87dcfdc73 100644 --- a/.github/workflows/analyze.yml +++ b/.github/workflows/analyze.yml @@ -16,7 +16,7 @@ jobs: - name: Set up node uses: actions/setup-node@v1 with: - node-version: "14.x" + node-version: '20.x' - name: Install dependencies uses: bahmutov/npm-install@v1.7.10 diff --git a/.github/workflows/site_lint.yml b/.github/workflows/site_lint.yml index bf446393a..560e22643 100644 --- a/.github/workflows/site_lint.yml +++ b/.github/workflows/site_lint.yml @@ -11,14 +11,14 @@ jobs: lint: runs-on: ubuntu-latest - name: Lint on node 12.x and ubuntu-latest + name: Lint on node 20.x and ubuntu-latest steps: - uses: actions/checkout@v1 - - name: Use Node.js 12.x + - name: Use Node.js 20.x uses: actions/setup-node@v1 with: - node-version: 12.x + node-version: 20.x - name: Install deps and build (with cache) uses: bahmutov/npm-install@v1.7.10 diff --git a/next.config.js b/next.config.js index 2ea3e916e..414728580 100644 --- a/next.config.js +++ b/next.config.js @@ -9,10 +9,10 @@ const nextConfig = { pageExtensions: ['jsx', 'js', 'ts', 'tsx', 'mdx', 'md'], reactStrictMode: true, experimental: { - plugins: true, + // TODO: Remove after https://github.com/vercel/next.js/issues/49355 is fixed + appDir: false, scrollRestoration: true, legacyBrowsers: false, - browsersListForSwc: true, }, env: { SANDPACK_BARE_COMPONENTS: process.env.SANDPACK_BARE_COMPONENTS, diff --git a/package.json b/package.json index f4f9a8026..e12f2aa46 100644 --- a/package.json +++ b/package.json @@ -32,12 +32,12 @@ "debounce": "^1.2.1", "ga-lite": "^2.1.4", "github-slugger": "^1.3.0", - "next": "12.3.2-canary.7", + "next": "^13.4.1", "next-remote-watch": "^1.0.0", "parse-numeric-range": "^1.2.0", - "react": "0.0.0-experimental-cb5084d1c-20220924", + "react": "^0.0.0-experimental-16d053d59-20230506", "react-collapsed": "npm:@gaearon/react-collapsed@3.1.0-forked.1", - "react-dom": "0.0.0-experimental-cb5084d1c-20220924", + "react-dom": "^0.0.0-experimental-16d053d59-20230506", "remark-frontmatter": "^4.0.1", "remark-gfm": "^3.0.1" }, @@ -98,7 +98,7 @@ "webpack-bundle-analyzer": "^4.5.0" }, "engines": { - "node": ">=12.x" + "node": "^16.8.0 || ^18.0.0 || ^19.0.0 || ^20.0.0" }, "nextBundleAnalysis": { "budget": null, diff --git a/patches/next+12.3.2-canary.7.patch b/patches/next+12.3.2-canary.7.patch deleted file mode 100644 index ee8d132de..000000000 --- a/patches/next+12.3.2-canary.7.patch +++ /dev/null @@ -1,22 +0,0 @@ -diff --git a/node_modules/next/dist/server/render.js b/node_modules/next/dist/server/render.js -index 3a141de..72a8749 100644 ---- a/node_modules/next/dist/server/render.js -+++ b/node_modules/next/dist/server/render.js -@@ -752,9 +752,14 @@ async function renderToHTML(req, res, pathname, query, renderOpts) { - // Enabling react concurrent rendering mode: __NEXT_REACT_ROOT = true - const renderShell = async (EnhancedApp, EnhancedComponent)=>{ - const content = renderContent(EnhancedApp, EnhancedComponent); -- return await (0, _nodeWebStreamsHelper).renderToInitialStream({ -- ReactDOMServer, -- element: content -+ return new Promise((resolve, reject) => { -+ (0, _nodeWebStreamsHelper).renderToInitialStream({ -+ ReactDOMServer, -+ element: content, -+ streamOptions: { -+ onError: reject -+ } -+ }).then(resolve, reject); - }); - }; - const createBodyResult = (initialStream, suffix)=>{ diff --git a/patches/next+13.4.1.patch b/patches/next+13.4.1.patch new file mode 100644 index 000000000..6de490aa4 --- /dev/null +++ b/patches/next+13.4.1.patch @@ -0,0 +1,22 @@ +diff --git a/node_modules/next/dist/server/render.js b/node_modules/next/dist/server/render.js +index a1f8648..1b3d608 100644 +--- a/node_modules/next/dist/server/render.js ++++ b/node_modules/next/dist/server/render.js +@@ -758,9 +758,14 @@ async function renderToHTML(req, res, pathname, query, renderOpts) { + // Always using react concurrent rendering mode with required react version 18.x + const renderShell = async (EnhancedApp, EnhancedComponent)=>{ + const content = renderContent(EnhancedApp, EnhancedComponent); +- return await (0, _nodewebstreamshelper.renderToInitialStream)({ +- ReactDOMServer: _serverbrowser.default, +- element: content ++ return new Promise((resolve, reject) => { ++ (0, _nodewebstreamshelper.renderToInitialStream)({ ++ ReactDOMServer: _serverbrowser.default, ++ element: content, ++ streamOptions: { ++ onError: reject ++ } ++ }).then(resolve, reject); + }); + }; + const createBodyResult = (0, _tracer.getTracer)().wrap(_constants2.RenderSpan.createBodyResult, (initialStream, suffix)=>{ diff --git a/src/components/Breadcrumbs.tsx b/src/components/Breadcrumbs.tsx index ca3afa851..8eead2302 100644 --- a/src/components/Breadcrumbs.tsx +++ b/src/components/Breadcrumbs.tsx @@ -15,10 +15,10 @@ function Breadcrumbs({breadcrumbs}: {breadcrumbs: RouteItem[]}) { !crumb.skipBreadcrumb && (
            - - - {crumb.title} - + + {crumb.title} & ButtonLinkProps) { const classes = cn( className, 'active:scale-[.98] transition-transform inline-flex font-bold items-center outline-none focus:outline-none focus-visible:outline focus-visible:outline-link focus:outline-offset-2 focus-visible:dark:focus:outline-link-dark leading-snug', @@ -34,10 +34,13 @@ function ButtonLink({ } ); return ( - - - {children} - + + {children} ); } diff --git a/src/components/DocsFooter.tsx b/src/components/DocsFooter.tsx index d2c2c25de..a5c7324e2 100644 --- a/src/components/DocsFooter.tsx +++ b/src/components/DocsFooter.tsx @@ -66,25 +66,24 @@ function FooterLink({ type: 'Previous' | 'Next'; }) { return ( - - - - - - {type} - - {title} + + + + + {type} - + {title} + ); } diff --git a/src/components/Layout/Footer.tsx b/src/components/Layout/Footer.tsx index 677899eec..4d0b06646 100644 --- a/src/components/Layout/Footer.tsx +++ b/src/components/Layout/Footer.tsx @@ -388,8 +388,8 @@ function FooterLink({ return (
            - - {children} + + {children}
            ); diff --git a/src/components/Layout/HomeContent.js b/src/components/Layout/HomeContent.js index 5ff366d31..ba3ff6ef1 100644 --- a/src/components/Layout/HomeContent.js +++ b/src/components/Layout/HomeContent.js @@ -1186,13 +1186,14 @@ async function Talks({ confId }) { function useNestedScrollLock(ref) { useEffect(() => { + let node = ref.current; let isLocked = false; let lastScroll = performance.now(); function handleScroll() { if (!isLocked) { isLocked = true; - ref.current.style.pointerEvents = 'none'; + node.style.pointerEvents = 'none'; } lastScroll = performance.now(); } @@ -1200,7 +1201,7 @@ function useNestedScrollLock(ref) { function updateLock() { if (isLocked && performance.now() - lastScroll > 150) { isLocked = false; - ref.current.style.pointerEvents = ''; + node.style.pointerEvents = ''; } } diff --git a/src/components/Layout/Sidebar/SidebarLink.tsx b/src/components/Layout/Sidebar/SidebarLink.tsx index 6889a4b10..050bf7c71 100644 --- a/src/components/Layout/Sidebar/SidebarLink.tsx +++ b/src/components/Layout/Sidebar/SidebarLink.tsx @@ -49,44 +49,43 @@ export function SidebarLink({ target = '_blank'; } return ( - - 0, - 'pl-5': level < 2, - 'text-base font-bold': level === 0, - 'text-primary dark:text-primary-dark': level === 0 && !selected, - 'text-base text-secondary dark:text-secondary-dark': - level > 0 && !selected, - 'text-base text-link dark:text-link-dark bg-highlight dark:bg-highlight-dark border-blue-40 hover:bg-highlight hover:text-link dark:hover:bg-highlight-dark dark:hover:text-link-dark': - selected, - 'dark:bg-gray-70 bg-gray-3 dark:hover:bg-gray-70 hover:bg-gray-3': - isPending, - } - )}> - {/* This here needs to be refactored ofc */} + 0, + 'pl-5': level < 2, + 'text-base font-bold': level === 0, + 'text-primary dark:text-primary-dark': level === 0 && !selected, + 'text-base text-secondary dark:text-secondary-dark': + level > 0 && !selected, + 'text-base text-link dark:text-link-dark bg-highlight dark:bg-highlight-dark border-blue-40 hover:bg-highlight hover:text-link dark:hover:bg-highlight-dark dark:hover:text-link-dark': + selected, + 'dark:bg-gray-70 bg-gray-3 dark:hover:bg-gray-70 hover:bg-gray-3': + isPending, + } + )}> + {/* This here needs to be refactored ofc */} + + {title} + + {isExpanded != null && !hideArrow && ( - {title} + - {isExpanded != null && !hideArrow && ( - - - - )} - + )} ); } diff --git a/src/components/Layout/TopNav/TopNav.tsx b/src/components/Layout/TopNav/TopNav.tsx index 23860a16f..0157f1ba5 100644 --- a/src/components/Layout/TopNav/TopNav.tsx +++ b/src/components/Layout/TopNav/TopNav.tsx @@ -90,15 +90,17 @@ const githubIcon = ( ); -function Link({href, children, ...props}: JSX.IntrinsicElements['a']) { +function Link({ + href, + children, + ...props +}: React.AnchorHTMLAttributes) { return ( - - {/* eslint-disable-next-line jsx-a11y/anchor-has-content */} - - {children} - + + {children} ); } @@ -247,16 +249,15 @@ export default function TopNav({ {isOpen ? : }
            - - - - React - + + + React
            diff --git a/src/components/MDX/BlogCard.tsx b/src/components/MDX/BlogCard.tsx index 9d86f9211..ba610b111 100644 --- a/src/components/MDX/BlogCard.tsx +++ b/src/components/MDX/BlogCard.tsx @@ -16,62 +16,62 @@ export interface BlogCardProps { function BlogCard({title, badge, date, icon, url, children}: BlogCardProps) { return ( - - -
            -
            -

            - {title} -

            -
            -
            -
            - {icon === 'labs' && ( - - - - )} - {icon === 'blog' && ( - - - - )} - {date} - {badge ? ( -
            - New -
            - ) : null} -
            - - {children} - - {children != null && ( -
            - Read more -
            + +
            ); } diff --git a/src/components/MDX/Link.tsx b/src/components/MDX/Link.tsx index 8986d07a5..7bf041e56 100644 --- a/src/components/MDX/Link.tsx +++ b/src/components/MDX/Link.tsx @@ -13,7 +13,7 @@ function Link({ className, children, ...props -}: JSX.IntrinsicElements['a']) { +}: React.AnchorHTMLAttributes) { const classes = 'inline text-link dark:text-link-dark border-b border-link border-opacity-0 hover:border-opacity-100 duration-100 ease-in transition leading-normal'; const modifiedChildren = Children.toArray(children).map((child: any) => { @@ -41,11 +41,8 @@ function Link({ {modifiedChildren}
            ) : ( - - {/* eslint-disable-next-line jsx-a11y/anchor-has-content */} - - {modifiedChildren} - + + {modifiedChildren} )} diff --git a/src/components/MDX/Sandpack/DownloadButton.tsx b/src/components/MDX/Sandpack/DownloadButton.tsx index 4181dbe95..4d206fff8 100644 --- a/src/components/MDX/Sandpack/DownloadButton.tsx +++ b/src/components/MDX/Sandpack/DownloadButton.tsx @@ -7,19 +7,22 @@ import {useSandpack} from '@codesandbox/sandpack-react'; import {IconDownload} from '../../Icon/IconDownload'; export interface DownloadButtonProps {} -let supportsImportMap: boolean | void; +let supportsImportMap = false; + +function subscribe(cb: () => void) { + // This shouldn't actually need to update, but this works around + // https://github.com/facebook/react/issues/26095 + let timeout = setTimeout(() => { + supportsImportMap = + (HTMLScriptElement as any).supports && + (HTMLScriptElement as any).supports('importmap'); + cb(); + }, 0); + return () => clearTimeout(timeout); +} function useSupportsImportMap() { - function subscribe() { - // It never updates. - return () => {}; - } function getCurrentValue() { - if (supportsImportMap === undefined) { - supportsImportMap = - (HTMLScriptElement as any).supports && - (HTMLScriptElement as any).supports('importmap'); - } return supportsImportMap; } function getServerSnapshot() { diff --git a/src/components/Search.tsx b/src/components/Search.tsx index 0e8f84f0d..2a9743ec3 100644 --- a/src/components/Search.tsx +++ b/src/components/Search.tsx @@ -22,11 +22,7 @@ export interface SearchProps { } function Hit({hit, children}: any) { - return ( - - {children} - - ); + return {children}; } // Copy-pasted from @docsearch/react to avoid importing the whole bundle. diff --git a/yarn.lock b/yarn.lock index 5aa76ffbe..d6e0c82c1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -896,10 +896,10 @@ unist-util-visit "^4.0.0" vfile "^5.0.0" -"@next/env@12.3.2-canary.7": - version "12.3.2-canary.7" - resolved "https://registry.yarnpkg.com/@next/env/-/env-12.3.2-canary.7.tgz#98cf3ed5e7d6af93965c708799ac02cb46ca3831" - integrity sha512-uk5yDvh8ra8PlIczZBTZKyt5Rf6a6mH2tGB3hwRAXD5hVLd74LzBQza2aYMEcDlRafAknsbL0dnqI3CkFYat9w== +"@next/env@13.4.1": + version "13.4.1" + resolved "https://registry.yarnpkg.com/@next/env/-/env-13.4.1.tgz#57322da2630b6bb6d7204577b0a18f6f9324db0c" + integrity sha512-eD6WCBMFjLFooLM19SIhSkWBHtaFrZFfg2Cxnyl3vS3DAdFRfnx5TY2RxlkuKXdIRCC0ySbtK9JXXt8qLCqzZg== "@next/eslint-plugin-next@12.0.3": version "12.0.3" @@ -908,70 +908,50 @@ dependencies: glob "7.1.7" -"@next/swc-android-arm-eabi@12.3.2-canary.7": - version "12.3.2-canary.7" - resolved "https://registry.yarnpkg.com/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-12.3.2-canary.7.tgz#21811767685d8a58756bbfff23a4e61c8da65a15" - integrity sha512-pusM/ylasGBweiwhINtqWCgy5bOjLmIctFD0etpmh9+DqCg09yu58hJ1Dn/UTW8EbB1nkTP1z3dEoMKLh4fV2A== - -"@next/swc-android-arm64@12.3.2-canary.7": - version "12.3.2-canary.7" - resolved "https://registry.yarnpkg.com/@next/swc-android-arm64/-/swc-android-arm64-12.3.2-canary.7.tgz#278e709c31ac5aceebd5e7f66efb81dae40ccab6" - integrity sha512-x11T0ocPE9xrnqMeDzUMepN3P8CHIN8iiLgiFkbTbKTbSciuH3juOvKggJO9APZRG5Ch5eePWcCy2gHedAbhnA== - -"@next/swc-darwin-arm64@12.3.2-canary.7": - version "12.3.2-canary.7" - resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.3.2-canary.7.tgz#7858ecf88a4e252ef6b66c59e38449a79647e362" - integrity sha512-tcO9hDaMfcbiaZp1B+HZcLzGGs36dnmjQ0YXyn6C88HEUoKyxanYleVHtTmWHlgsxxjZdDd/RzOze1ycWs2oXw== - -"@next/swc-darwin-x64@12.3.2-canary.7": - version "12.3.2-canary.7" - resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-12.3.2-canary.7.tgz#9225324b6de548ce7fd21c31d4725910c5b7d136" - integrity sha512-WjAyU67zj69nRM2GNAnBLvghq4EHTyDzMO02GjG6yexVhDvkE0OFlvh0BQLI3DIOz+B3RjJRcW3OoHi8XzW9UA== - -"@next/swc-freebsd-x64@12.3.2-canary.7": - version "12.3.2-canary.7" - resolved "https://registry.yarnpkg.com/@next/swc-freebsd-x64/-/swc-freebsd-x64-12.3.2-canary.7.tgz#cf3374f2c3ddf370ed27cac84258760b282b6981" - integrity sha512-cQrdPCMhP1Mc+pIt16FlC5BVgcXzLXRlm7qZ7wBRKG6r/IIIn/qNRFgQQcB3iyvfNZo7lURLKcfsxNmMGclldQ== - -"@next/swc-linux-arm-gnueabihf@12.3.2-canary.7": - version "12.3.2-canary.7" - resolved "https://registry.yarnpkg.com/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.3.2-canary.7.tgz#b8e82ec743ceadfce25b7e74dfb447913b603c44" - integrity sha512-LEL+dUe10FhQHyXq9Mul5pOJwKDtrAylh9chktWf8eFr14j/YrfPbkLHv1+tCK8brDV3afVJMl0IpoCo75Yfyg== - -"@next/swc-linux-arm64-gnu@12.3.2-canary.7": - version "12.3.2-canary.7" - resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.3.2-canary.7.tgz#1711f46f004553f3c8ab7546b49e65f88abbbfd6" - integrity sha512-mbDqHk3C76UGIzkOv+G5NslKiSYIXyWQwbkuty0+0wLVJttWjWi2dMN7DFJQPMNvBefU9/vxVJdUnGVGEZfUXw== - -"@next/swc-linux-arm64-musl@12.3.2-canary.7": - version "12.3.2-canary.7" - resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.3.2-canary.7.tgz#e20b71ce215280bc2cadcf94f9755fdf3ffc0b24" - integrity sha512-gJ3VQHuqb3ABiOKPxfWAJQdO4mp3yNnWIAPN8n52F7Zu38udbHXvcbIylWfQW/Qah+RRf7P7y2txH2kC07QOPA== - -"@next/swc-linux-x64-gnu@12.3.2-canary.7": - version "12.3.2-canary.7" - resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.3.2-canary.7.tgz#176cf50080f121537877dbdfb7d667be19333a8c" - integrity sha512-/PBLiC+JfMJIzwMCQaSQgnLoIOjdSjTA9zarj2Kk1eCLjH8/VnsfBWtmP7TdbgIRYnZ8QKb4HXSOq94ZQS/fkw== - -"@next/swc-linux-x64-musl@12.3.2-canary.7": - version "12.3.2-canary.7" - resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.3.2-canary.7.tgz#96b858043d76b87f90b7da43afe13c5942dbceea" - integrity sha512-Bf3goHoUd0SB58sVTMva0ByoLM+aEhm5YJRqsi7SsOAu9EAQwYfWgY2Hx60ah5i1N4ihYK0xjs8kwlfdDVOuow== - -"@next/swc-win32-arm64-msvc@12.3.2-canary.7": - version "12.3.2-canary.7" - resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.3.2-canary.7.tgz#dd1a36d4afbecc623e71426897cea683a3a75666" - integrity sha512-aPRQ4dY5MuLgHCVdY+/Grgg4oX38pG4S0sT8mpatK3oIdjhj3961cj33QpPAy6dhhCs8m0/eCWYmM9KKlAAUsg== - -"@next/swc-win32-ia32-msvc@12.3.2-canary.7": - version "12.3.2-canary.7" - resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.3.2-canary.7.tgz#a7455ea57f88345a92c0067e82aa1b7aa5728088" - integrity sha512-hr+TBDICVezyn0HDK4QootalbcuLj9F8qUzZZAw3gHz16rUDpqpnlRjw3RC99AzkKL7qMsdR/+SwnBlBY7ZK7Q== - -"@next/swc-win32-x64-msvc@12.3.2-canary.7": - version "12.3.2-canary.7" - resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.3.2-canary.7.tgz#4e0d6d567c254e2cf00738f876ddafe5b611ee03" - integrity sha512-1n29b6meb54h/Mw/1xPoJB682nWbtEsUQo7rFJ6G44Nj3fYFXe+XOWQxWu6Sl8yvdBXcZRhRCHuAZGqYtmqorQ== +"@next/swc-darwin-arm64@13.4.1": + version "13.4.1" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.4.1.tgz#3748040d2dd0d89d3cdcc897f96aeda5130eed8f" + integrity sha512-eF8ARHtYfnoYtDa6xFHriUKA/Mfj/cCbmKb3NofeKhMccs65G6/loZ15a6wYCCx4rPAd6x4t1WmVYtri7EdeBg== + +"@next/swc-darwin-x64@13.4.1": + version "13.4.1" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-13.4.1.tgz#c59fc270005f17e04eb7eab4fd68793d0e3409a4" + integrity sha512-7cmDgF9tGWTgn5Gw+vP17miJbH4wcraMHDCOHTYWkO/VeKT73dUWG23TNRLfgtCNSPgH4V5B4uLHoZTanx9bAw== + +"@next/swc-linux-arm64-gnu@13.4.1": + version "13.4.1" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.4.1.tgz#1aef371bcef5d832d7f7e3aec3e68cfb98282393" + integrity sha512-qwJqmCri2ie8aTtE5gjTSr8S6O8B67KCYgVZhv9gKH44yvc/zXbAY8u23QGULsYOyh1islWE5sWfQNLOj9iryg== + +"@next/swc-linux-arm64-musl@13.4.1": + version "13.4.1" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.4.1.tgz#2522927cb0af6918405a49f5a1d1687d6847f3ec" + integrity sha512-qcC54tWNGDv/VVIFkazxhqH1Bnagjfs4enzELVRlUOoJPD2BGJTPI7z08pQPbbgxLtRiu8gl2mXvpB8WlOkMeA== + +"@next/swc-linux-x64-gnu@13.4.1": + version "13.4.1" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.4.1.tgz#5ec9418a35510048a5ceb79ed300463e1a9b312d" + integrity sha512-9TeWFlpLsBosZ+tsm/rWBaMwt5It9tPH8m3nawZqFUUrZyGRfGcI67js774vtx0k3rL9qbyY6+3pw9BCVpaYUA== + +"@next/swc-linux-x64-musl@13.4.1": + version "13.4.1" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.4.1.tgz#3478b9c89b75c1d0e7def9f35a9a77cb15d1a115" + integrity sha512-sNDGaWmSqTS4QRUzw61wl4mVPeSqNIr1OOjLlQTRuyInxMxtqImRqdvzDvFTlDfdeUMU/DZhWGYoHrXLlZXe6A== + +"@next/swc-win32-arm64-msvc@13.4.1": + version "13.4.1" + resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.4.1.tgz#efe53d48ff51d2485eabb910ab7caee78425fc01" + integrity sha512-+CXZC7u1iXdLRudecoUYbhbsXpglYv8KFYsFxKBPn7kg+bk7eJo738wAA4jXIl8grTF2mPdmO93JOQym+BlYGA== + +"@next/swc-win32-ia32-msvc@13.4.1": + version "13.4.1" + resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.4.1.tgz#952cdf1c53df46a90d5151d99310195d2c384e55" + integrity sha512-vIoXVVc7UYO68VwVMDKwJC2+HqAZQtCYiVlApyKEeIPIQpz2gpufzGxk1z3/gwrJt/kJ5CDZjlhYDCzd3hdz+g== + +"@next/swc-win32-x64-msvc@13.4.1": + version "13.4.1" + resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.4.1.tgz#447b7dcee5f5d4824cdff331a4ec34b13d0b449d" + integrity sha512-n8V5ImLQZibKTu10UUdI3nIeTLkliEXe628qxqW9v8My3BAH2a7H0SaCqkV2OgqFnn8sG1wxKYw9/SNJ632kSA== "@nodelib/fs.scandir@2.1.5": version "2.1.5" @@ -1022,10 +1002,10 @@ resolved "https://registry.yarnpkg.com/@stitches/core/-/core-1.2.8.tgz#dce3b8fdc764fbc6dbea30c83b73bfb52cf96173" integrity sha512-Gfkvwk9o9kE9r9XNBmJRfV8zONvXThnm1tcuojL04Uy5uRyqg93DC83lDebl0rocZCfKSjUv+fWYtMQmEDJldg== -"@swc/helpers@0.4.11": - version "0.4.11" - resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.4.11.tgz#db23a376761b3d31c26502122f349a21b592c8de" - integrity sha512-rEUrBSGIoSFuYxwBYtlUFMlE2CwGhmW+w9355/5oduSw8e5h2+Tj4UrAGNNgP9915++wj5vkQo0UuOBqOAq4nw== +"@swc/helpers@0.5.1": + version "0.5.1" + resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.1.tgz#e9031491aa3f26bfcc974a67f48bd456c8a5357a" + integrity sha512-sJ902EfIzn1Fa+qYmjdQqh8tPsoxyBz+8yBKC2HKUxyezKJFwPGOn7pv4WY6QuQW//ySQi5lJjA/ZT9sNWWNTg== dependencies: tslib "^2.4.0" @@ -1684,6 +1664,13 @@ browserslist@^4.20.2: node-releases "^2.0.6" update-browserslist-db "^1.0.5" +busboy@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/busboy/-/busboy-1.6.0.tgz#966ea36a9502e43cdb9146962523b92f531f6893" + integrity sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA== + dependencies: + streamsearch "^1.1.0" + bytes@3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" @@ -1852,6 +1839,11 @@ cli-truncate@^3.1.0: slice-ansi "^5.0.0" string-width "^5.0.0" +client-only@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/client-only/-/client-only-0.0.1.tgz#38bba5d403c41ab150bff64a95c85013cf73bca1" + integrity sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA== + codesandbox-import-util-types@^1.3.7: version "1.3.7" resolved "https://registry.yarnpkg.com/codesandbox-import-util-types/-/codesandbox-import-util-types-1.3.7.tgz#7a6097e248a75424d13b06b74368cd76bd2b3e10" @@ -4488,31 +4480,28 @@ next-tick@^1.1.0: resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.1.0.tgz#1836ee30ad56d67ef281b22bd199f709449b35eb" integrity sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ== -next@12.3.2-canary.7: - version "12.3.2-canary.7" - resolved "https://registry.yarnpkg.com/next/-/next-12.3.2-canary.7.tgz#c739348174a3d7d97a638aa409376a96577a31d8" - integrity sha512-zUosveWzpeRVy7j4ANoJ4gu0TBrkLYwPlIUEXrqqs/zLpHMu+tanxA1R1ts2d7h/2dSmeVZgGcHiVcHj5uspEA== +next@^13.4.1: + version "13.4.1" + resolved "https://registry.yarnpkg.com/next/-/next-13.4.1.tgz#8d23f94c81b3f9cc8b34165ad528457e5befd726" + integrity sha512-JBw2kAIyhKDpjhEWvNVoFeIzNp9xNxg8wrthDOtMctfn3EpqGCmW0FSviNyGgOSOSn6zDaX48pmvbdf6X2W9xA== dependencies: - "@next/env" "12.3.2-canary.7" - "@swc/helpers" "0.4.11" + "@next/env" "13.4.1" + "@swc/helpers" "0.5.1" + busboy "1.6.0" caniuse-lite "^1.0.30001406" postcss "8.4.14" - styled-jsx "5.0.7" - use-sync-external-store "1.2.0" + styled-jsx "5.1.1" + zod "3.21.4" optionalDependencies: - "@next/swc-android-arm-eabi" "12.3.2-canary.7" - "@next/swc-android-arm64" "12.3.2-canary.7" - "@next/swc-darwin-arm64" "12.3.2-canary.7" - "@next/swc-darwin-x64" "12.3.2-canary.7" - "@next/swc-freebsd-x64" "12.3.2-canary.7" - "@next/swc-linux-arm-gnueabihf" "12.3.2-canary.7" - "@next/swc-linux-arm64-gnu" "12.3.2-canary.7" - "@next/swc-linux-arm64-musl" "12.3.2-canary.7" - "@next/swc-linux-x64-gnu" "12.3.2-canary.7" - "@next/swc-linux-x64-musl" "12.3.2-canary.7" - "@next/swc-win32-arm64-msvc" "12.3.2-canary.7" - "@next/swc-win32-ia32-msvc" "12.3.2-canary.7" - "@next/swc-win32-x64-msvc" "12.3.2-canary.7" + "@next/swc-darwin-arm64" "13.4.1" + "@next/swc-darwin-x64" "13.4.1" + "@next/swc-linux-arm64-gnu" "13.4.1" + "@next/swc-linux-arm64-musl" "13.4.1" + "@next/swc-linux-x64-gnu" "13.4.1" + "@next/swc-linux-x64-musl" "13.4.1" + "@next/swc-win32-arm64-msvc" "13.4.1" + "@next/swc-win32-ia32-msvc" "13.4.1" + "@next/swc-win32-x64-msvc" "13.4.1" nice-try@^1.0.4: version "1.0.5" @@ -5357,13 +5346,13 @@ react-devtools-inline@4.4.0: dependencies: es6-symbol "^3" -react-dom@0.0.0-experimental-cb5084d1c-20220924: - version "0.0.0-experimental-cb5084d1c-20220924" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-0.0.0-experimental-cb5084d1c-20220924.tgz#7a8334c5cf4baeb5651ca76fc9eb92ebbaf223bf" - integrity sha512-0IHzPGHESn3uu8nI1w5596GX8bCGCE94DpaHkKSGWOlB6uhoVecU0fyOCkkNuB4cMc9WeOWiH2gsM100EWZDPQ== +react-dom@^0.0.0-experimental-16d053d59-20230506: + version "0.0.0-experimental-16d053d59-20230506" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-0.0.0-experimental-16d053d59-20230506.tgz#1870c355f1027262992b2226191810ba15eedab3" + integrity sha512-I4PIT9ZAdDgpbav9BxfzPv2p5otJz6BEbFEBvFwd1BnQJmtkKKApUU7RYdGKnwY2/r6hdfxPm2pne+NhiyBkzg== dependencies: loose-envify "^1.1.0" - scheduler "0.0.0-experimental-cb5084d1c-20220924" + scheduler "0.0.0-experimental-16d053d59-20230506" react-is@^16.13.1: version "16.13.1" @@ -5375,10 +5364,10 @@ react-is@^17.0.2: resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== -react@0.0.0-experimental-cb5084d1c-20220924: - version "0.0.0-experimental-cb5084d1c-20220924" - resolved "https://registry.yarnpkg.com/react/-/react-0.0.0-experimental-cb5084d1c-20220924.tgz#ab661af674be824ae2989467506443b8bc4318d3" - integrity sha512-66AdfxkJrwCaCEKT0LQRd9J9GQ9T+yN7Wx9XT+tNxKycYQ0Exm+DZxOTedagWDlsFMXroyhrTWzgdC18R2PaOQ== +react@^0.0.0-experimental-16d053d59-20230506: + version "0.0.0-experimental-16d053d59-20230506" + resolved "https://registry.yarnpkg.com/react/-/react-0.0.0-experimental-16d053d59-20230506.tgz#98a7a9d19ab1820f882111ce4fc4e23f3cb8aaad" + integrity sha512-8PdloFcanNcryJLohpr4rVQfB4oJvsL0Z+TzJ8B66RxauwF95QqUNorGsK1heESrtj4As0oHCmiZkoYzA4uW8w== dependencies: loose-envify "^1.1.0" @@ -5709,10 +5698,10 @@ safe-buffer@~5.1.1: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -scheduler@0.0.0-experimental-cb5084d1c-20220924: - version "0.0.0-experimental-cb5084d1c-20220924" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.0.0-experimental-cb5084d1c-20220924.tgz#9986680e1fbf7e4ccfe7606fef5920939d3a1abe" - integrity sha512-SeszKCdhM5OHxNMStjpKIAaloARUMZqIpDZjkZeGuRsyr7YlAqvlsCXyee4ZQOOU1pbr7BIvQntKy5Hil+DQJA== +scheduler@0.0.0-experimental-16d053d59-20230506: + version "0.0.0-experimental-16d053d59-20230506" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.0.0-experimental-16d053d59-20230506.tgz#cb76957af2849452a5e40c82fb53168da255e32f" + integrity sha512-gGnyU4CkC/+msd1dOQW9zuquI3GoEziuS42soP0AvbTCvRkeU4qhR/mRRaU+/a7JK/OFeSSudcz7enkrkZdSPA== dependencies: loose-envify "^1.1.0" @@ -5941,6 +5930,11 @@ statuses@2.0.1: resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== +streamsearch@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764" + integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg== + string-argv@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.1.tgz#95e2fbec0427ae19184935f816d74aaa4c5c19da" @@ -6066,10 +6060,12 @@ style-to-object@^0.3.0: dependencies: inline-style-parser "0.1.1" -styled-jsx@5.0.7: - version "5.0.7" - resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-5.0.7.tgz#be44afc53771b983769ac654d355ca8d019dff48" - integrity sha512-b3sUzamS086YLRuvnaDigdAewz1/EFYlHpYBP5mZovKEdQQOIIYq8lApylub3HHZ6xFjV051kkGU7cudJmrXEA== +styled-jsx@5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-5.1.1.tgz#839a1c3aaacc4e735fed0781b8619ea5d0009d1f" + integrity sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw== + dependencies: + client-only "0.0.1" supports-color@^5.3.0: version "5.5.0" @@ -6494,11 +6490,6 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" -use-sync-external-store@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a" - integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA== - util-deprecate@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" @@ -6684,6 +6675,11 @@ yaml@^1.10.0, yaml@^1.10.2: resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== +zod@3.21.4: + version "3.21.4" + resolved "https://registry.yarnpkg.com/zod/-/zod-3.21.4.tgz#10882231d992519f0a10b5dd58a38c9dabbb64db" + integrity sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw== + zwitch@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/zwitch/-/zwitch-2.0.2.tgz#91f8d0e901ffa3d66599756dde7f57b17c95dce1" From da6fed9f282e82fc63e34171b3bb6e12609afded Mon Sep 17 00:00:00 2001 From: Palidos <36964844+Palidos@users.noreply.github.com> Date: Fri, 19 May 2023 21:16:19 +0300 Subject: [PATCH 149/233] add another round of fixes --- src/content/learn/installation.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/content/learn/installation.md b/src/content/learn/installation.md index 47e628a5b..102f394f8 100644 --- a/src/content/learn/installation.md +++ b/src/content/learn/installation.md @@ -17,9 +17,9 @@ React был спроектирован с самого начала с учёт -## Пробуем React {/*try-react*/} +## Попробовать React {/*try-react*/} -Чтобы попробовать React, даже устанавливать ничего не нужно. Редактируйте прямо в песочнице! +Чтобы попробовать React, даже устанавливать ничего не нужно. Поредактируйте код в песочнице! @@ -39,9 +39,9 @@ export default function App() { Такие песочницы есть на большинстве страниц React-документации. За пределами React-документации также есть большое количество песочниц, поддерживающих React. Например: [CodeSandbox](https://codesandbox.io/s/new), [StackBlitz](https://stackblitz.com/fork/react) или [CodePen.](https://codepen.io/pen?&editors=0010&layout=left&prefill_data_id=3f4569d1-1b11-4bce-bd46-89090eed5ddb) -### Поиграть с React локально {/*try-react-locally*/} +### Попробовать React локально {/*try-react-locally*/} -Что бы поиграть с React локально на вашем компьютере, [скачайте эту HTML страницу.](https://gist.githubusercontent.com/gaearon/0275b1e1518599bbeafcde4722e79ed1/raw/db72dcbf3384ee1708c4a07d3be79860db04bff0/example.html) Откройте её в своем текстовом редакторе и браузере! +Чтобы попробовать React локально на вашем компьютере, [скачайте эту HTML страницу.](https://gist.githubusercontent.com/gaearon/0275b1e1518599bbeafcde4722e79ed1/raw/db72dcbf3384ee1708c4a07d3be79860db04bff0/example.html) Откройте её в своем текстовом редакторе и браузере! ## Начать новый React-проект {/*start-a-new-react-project*/} @@ -49,9 +49,9 @@ export default function App() { ## Добавить React в существующий проект {/*add-react-to-an-existing-project*/} -Если вы хотите использовать React в существующем приложении или сайте — [добавьте React в существующий проект.](/learn/add-react-to-an-existing-project) +Если вы хотите попробовать React в существующем приложении или сайте — [добавьте React в существующий проект.](/learn/add-react-to-an-existing-project) ## Дальнейшие шаги {/*next-steps*/} -Перейдите к [Введению в React](/learn) для ознакомления с самыми важными его концепциями, с которыми вы будете сталкиваться каждый день. +Перейдите к [Введению в React](/learn) чтобы ознакомиться с его важнейшими концепциями, которые вы будете встречать каждый день. From 3e9b50bc9380d86279aee34d6d0126620d34a1cc Mon Sep 17 00:00:00 2001 From: Konstantin Arabei Date: Mon, 22 May 2023 01:30:47 +0400 Subject: [PATCH 150/233] fix gap before step 2 --- src/content/learn/your-first-component.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/content/learn/your-first-component.md b/src/content/learn/your-first-component.md index 23c0eb957..c962c2b63 100644 --- a/src/content/learn/your-first-component.md +++ b/src/content/learn/your-first-component.md @@ -81,6 +81,7 @@ img { height: 200px; } ### Шаг 1: Экспортировать компонент {/*step-1-export-the-component*/} Префикс `export default` — это [стандартный синтаксис JavaScript](https://developer.mozilla.org/ru/docs/web/javascript/reference/statements/export) (не является спецификой React). Он позволяет пометить основную функцию в файле, чтобы её можно было импортировать из других файлов. (Подробнее об импорте в [Импорт и Экспорт компонентов](/learn/importing-and-exporting-components)!) + ### Шаг 2: Определить функцию {/*step-2-define-the-function*/} С помощью `function Profile() { }` вы определяете JavaScript-функцию с именем `Profile`. From 7413d7645612a7da2e8d16316832c17d36707dfb Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Mon, 22 May 2023 07:19:30 +0300 Subject: [PATCH 151/233] Update src/content/learn/render-and-commit.md Co-authored-by: Anton Ahatov --- src/content/learn/render-and-commit.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/render-and-commit.md b/src/content/learn/render-and-commit.md index dc44fa9a8..897948bcb 100644 --- a/src/content/learn/render-and-commit.md +++ b/src/content/learn/render-and-commit.md @@ -131,7 +131,7 @@ img { margin: 0 10px 10px 0; } Рендеринг должен всегда быть [pure calculation](/learn/keeping-components-pure): -* **Одинаковые входные данные, одинаковые выходящие.** При одинаковых входящих данных компонент всегда должен возвращать один и тот же JSX. (Когда кто-то заказывает салат с помидорами, то он не должен получить салат с луком!) +* **Одни и те же входные данные, один и тот же результат.** При одинаковых входящих данных компонент всегда должен возвращать один и тот же JSX. (Когда кто-то заказывает салат с помидорами, то он не должен получить салат с луком!) * **Своими делами заниматься.** Не изменять объекты или переменные, существовавшие до рендеринга. (Один заказ не должен изменять чей-либо другой заказ). В противном случае вы можете столкнуться с непонятными ошибками и непредсказуемым поведением по мере роста сложности вашей кодовой базы. При разработке в "строгом режиме" React вызывает функцию каждого компонента дважды, что может помочь выявить ошибки, вызванные нечистыми функциями. From f2153808a94dd8dc9220935d36cd8003624c1fb9 Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Mon, 22 May 2023 07:19:44 +0300 Subject: [PATCH 152/233] Update src/content/learn/render-and-commit.md Co-authored-by: Anton Ahatov --- src/content/learn/render-and-commit.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/render-and-commit.md b/src/content/learn/render-and-commit.md index 897948bcb..cdf935d7b 100644 --- a/src/content/learn/render-and-commit.md +++ b/src/content/learn/render-and-commit.md @@ -129,7 +129,7 @@ img { margin: 0 10px 10px 0; } -Рендеринг должен всегда быть [pure calculation](/learn/keeping-components-pure): +Рендеринг всегда должен быть [чистым вычислением.](/learn/keeping-components-pure): * **Одни и те же входные данные, один и тот же результат.** При одинаковых входящих данных компонент всегда должен возвращать один и тот же JSX. (Когда кто-то заказывает салат с помидорами, то он не должен получить салат с луком!) * **Своими делами заниматься.** Не изменять объекты или переменные, существовавшие до рендеринга. (Один заказ не должен изменять чей-либо другой заказ). From e4e703050989845f824c1c8663f3297b0fe99960 Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Mon, 22 May 2023 07:21:05 +0300 Subject: [PATCH 153/233] Update src/content/learn/render-and-commit.md Co-authored-by: Anton Ahatov --- src/content/learn/render-and-commit.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/render-and-commit.md b/src/content/learn/render-and-commit.md index cdf935d7b..033cdde78 100644 --- a/src/content/learn/render-and-commit.md +++ b/src/content/learn/render-and-commit.md @@ -153,7 +153,7 @@ img { margin: 0 10px 10px 0; } * **На начальном рендере,** React использует [`appendChild()`](https://developer.mozilla.org/ru/docs/Web/API/Node/appendChild) DOM API, чтобы вставить все DOM ноды, которые он создал на экране. * **Для ре-рендеров,** React будет применять минимально необходимые операции (вычисляемые во время рендеринга!), чтобы DOM соответствовал последнему выводу рендеринга. -** React изменяет узлы DOM, только если есть разница между рендерами.** Например, вот компонент, который рендерится с разными пропсами, передаваемыми от родителя каждую секунду. Обратите внимание, как вы можете добавить некоторый текст в ``, обновляя его `значение`, но текст не исчезает при повторном рендеринге компонента: +**React изменяет узлы DOM только если есть разница между рендерами.** Например, вот компонент, который рендерится с разными пропсами, передаваемыми от родителя каждую секунду. Обратите внимание, как вы можете добавить некоторый текст в ``, обновляя его `значение`, но текст не исчезает при повторном рендеринге компонента: From 7524338369d0b16cab05a631221061f6976752d3 Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Mon, 22 May 2023 07:21:36 +0300 Subject: [PATCH 154/233] Update src/content/learn/render-and-commit.md Co-authored-by: Anton Ahatov --- src/content/learn/render-and-commit.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/render-and-commit.md b/src/content/learn/render-and-commit.md index 033cdde78..643250c7b 100644 --- a/src/content/learn/render-and-commit.md +++ b/src/content/learn/render-and-commit.md @@ -196,7 +196,7 @@ export default function App() { Это работает, потому что в предыдущий раз, React обновил значение `

            ` с новым `time`. Он видит, что `` появляется в том же месте JSX, поэтому React не трогает ``— или его `value`! ## Epilogue: Browser paint {/*epilogue-browser-paint*/} -После того как рендеринг завершен и React обновил DOM, браузер перерисовывает экран. Хотя этот процесс известен как "браузерный рендеринг", мы будем называть его "рисованием", чтобы избежать путаницы в документации. +После того как рендеринг завершен и React обновил DOM, браузер перерисовывает экран. Хотя этот процесс известен как «браузерный рендеринг», мы будем называть его «рисованием», чтобы избежать путаницы в документации. From 857ddca8ff7c376e370f47f6666b8570b41811b1 Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Mon, 22 May 2023 07:22:03 +0300 Subject: [PATCH 155/233] Update src/content/learn/render-and-commit.md Co-authored-by: Anton Ahatov --- src/content/learn/render-and-commit.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/render-and-commit.md b/src/content/learn/render-and-commit.md index 643250c7b..1d8b09250 100644 --- a/src/content/learn/render-and-commit.md +++ b/src/content/learn/render-and-commit.md @@ -77,7 +77,7 @@ export default function Image() { ## Step 2: React рендерит ваш компонент {/*step-2-react-renders-your-components*/} -После запуска рендера React вызывает ваши компоненты, чтобы определить, что отобразить на экране. **"Рендеринг" — это обращение React к вашим компонентам*. +После запуска рендера React вызывает ваши компоненты, чтобы определить, что отобразить на экране. **«Рендеринг» — это обращение React к вашим компонентам*. * **На начальном рендере,** React вызовет корневой компонент. * **Для последующих рендерингов** React будет вызывать функцию компонента, обновление стейта которого вызвало рендеринг. From a5084bd7ce504aa624b8ec56a3b99c78aea33b44 Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Mon, 22 May 2023 07:22:21 +0300 Subject: [PATCH 156/233] Update src/content/learn/render-and-commit.md Co-authored-by: Anton Ahatov --- src/content/learn/render-and-commit.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/render-and-commit.md b/src/content/learn/render-and-commit.md index 1d8b09250..9ddf4f2af 100644 --- a/src/content/learn/render-and-commit.md +++ b/src/content/learn/render-and-commit.md @@ -193,7 +193,7 @@ export default function App() { -Это работает, потому что в предыдущий раз, React обновил значение `

            ` с новым `time`. Он видит, что `` появляется в том же месте JSX, поэтому React не трогает ``— или его `value`! +Это работает, потому что в предыдущий раз React обновил значение `

            ` с новым `time`. Он видит, что `` появляется в том же месте JSX, поэтому React не трогает ``— или его `value`! ## Epilogue: Browser paint {/*epilogue-browser-paint*/} После того как рендеринг завершен и React обновил DOM, браузер перерисовывает экран. Хотя этот процесс известен как «браузерный рендеринг», мы будем называть его «рисованием», чтобы избежать путаницы в документации. From 6b72d5efef59315ea1f437da52b4e9136f28f5d4 Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Mon, 22 May 2023 07:23:09 +0300 Subject: [PATCH 157/233] Update src/content/learn/render-and-commit.md Co-authored-by: Anton Ahatov --- src/content/learn/render-and-commit.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/render-and-commit.md b/src/content/learn/render-and-commit.md index 9ddf4f2af..c5cf92fc5 100644 --- a/src/content/learn/render-and-commit.md +++ b/src/content/learn/render-and-commit.md @@ -132,7 +132,7 @@ img { margin: 0 10px 10px 0; } Рендеринг всегда должен быть [чистым вычислением.](/learn/keeping-components-pure): * **Одни и те же входные данные, один и тот же результат.** При одинаковых входящих данных компонент всегда должен возвращать один и тот же JSX. (Когда кто-то заказывает салат с помидорами, то он не должен получить салат с луком!) -* **Своими делами заниматься.** Не изменять объекты или переменные, существовавшие до рендеринга. (Один заказ не должен изменять чей-либо другой заказ). +* **Занимается только своей задачей.** Не изменять объекты или переменные, существовавшие до рендеринга. (Один заказ не должен изменять чей-либо другой заказ). В противном случае вы можете столкнуться с непонятными ошибками и непредсказуемым поведением по мере роста сложности вашей кодовой базы. При разработке в "строгом режиме" React вызывает функцию каждого компонента дважды, что может помочь выявить ошибки, вызванные нечистыми функциями. From 7388007fa8ec1eaf632a8faf174404df95c410fc Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Mon, 22 May 2023 07:25:07 +0300 Subject: [PATCH 158/233] Update render-and-commit.md --- src/content/learn/render-and-commit.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/render-and-commit.md b/src/content/learn/render-and-commit.md index c5cf92fc5..a6261aa0e 100644 --- a/src/content/learn/render-and-commit.md +++ b/src/content/learn/render-and-commit.md @@ -132,7 +132,7 @@ img { margin: 0 10px 10px 0; } Рендеринг всегда должен быть [чистым вычислением.](/learn/keeping-components-pure): * **Одни и те же входные данные, один и тот же результат.** При одинаковых входящих данных компонент всегда должен возвращать один и тот же JSX. (Когда кто-то заказывает салат с помидорами, то он не должен получить салат с луком!) -* **Занимается только своей задачей.** Не изменять объекты или переменные, существовавшие до рендеринга. (Один заказ не должен изменять чей-либо другой заказ). +* **Занимается только своей задачей.** Не изменять объекты или переменные, существовавшие до рендеринга. (Один заказ не должен влиять на другой заказ). В противном случае вы можете столкнуться с непонятными ошибками и непредсказуемым поведением по мере роста сложности вашей кодовой базы. При разработке в "строгом режиме" React вызывает функцию каждого компонента дважды, что может помочь выявить ошибки, вызванные нечистыми функциями. From 326600a71d487284f58218a768a4d93daf3243b0 Mon Sep 17 00:00:00 2001 From: jewhyena <91225197+jewhyena@users.noreply.github.com> Date: Mon, 22 May 2023 10:45:53 +0300 Subject: [PATCH 159/233] Apply suggestions from code review Co-authored-by: Anton Ahatov --- src/content/reference/react/useMemo.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/content/reference/react/useMemo.md b/src/content/reference/react/useMemo.md index fe2b2a63a..ed56b5b92 100644 --- a/src/content/reference/react/useMemo.md +++ b/src/content/reference/react/useMemo.md @@ -34,7 +34,7 @@ function TodoList({ todos, tab }) { } ``` -[Больше примеров.](#usage) +[Больше примеров ниже.](#usage) #### Параметры {/*parameters*/} @@ -50,7 +50,7 @@ function TodoList({ todos, tab }) { #### Предостережения {/*caveats*/} -* Поскольку `useMemo` это хук, то вызывать его можно только **на верхнем уровне** внутри компонента или кастомного хука. Хуки нельзя вызывать внутри циклов или условий. Однако, если вам необходимо такое поведение, то можно извлечь новый компонент и переместить вызов хука в него. +* Поскольку `useMemo` это хук, то вызывать его можно только **на верхнем уровне внутри вашего компонента** или кастомного хука. Хуки нельзя вызывать внутри циклов или условий. Однако, если вам необходимо такое поведение, то можно извлечь новый компонент и переместить вызов хука в него. * В строгом режиме React дважды вызовет передаваемую в `useMemo` функцию, чтобы проверить, [является ли она чистой](#my-calculation-runs-twice-on-every-re-render). Такое поведение существует только в режиме разработки и никак не проявляется в продакшене. Если эта функция чистая (какой она и должна быть), это никак не скажется на работе приложения. Результат одного из запусков будет просто проигнорирован. * React **не отбрасывает закешированное значение, если на то нет веских причин**. Например, в режиме разработки React отбросит кеш, если файл компонента был изменён. В обоих режимах, разработки и продакшене, React отбросит кеш, если компонент [«задержится»](/reference/react/Suspense) во время первоначального монтирования. Помимо того, в дальнейшем в React могут быть добавлены новые возможности, которые смогут отбрасывать кеш. Например, если в будущем в React появится встроенная поддержка виртуализированных списков, будет иметь смысл отбрасывать кеш для тех элементов, которые выходят за область видимости. Полагаться на `useMemo` стоит только как на средство для оптимизации производительности. В противном случае, использование [состояния](/reference/react/useState#avoiding-recreating-the-initial-state) или [рефа](/reference/react/useRef#avoiding-recreating-the-ref-contents) может быть более подходящим вариантом. @@ -156,8 +156,8 @@ console.timeEnd('filter array'); **Излишней мемоизации можно избежать, следуя таким принципам:** 1. Когда один компонент визуально оборачивает другие компоненты, ему можно передать весь этот [JSX в виде дочерних компонентов](/learn/passing-props-to-a-component#passing-jsx-as-children). В таком случае, когда родительский компонент обновляет своё состояние, React будет знать, что дочерние компоненты не нуждаются в ререндере. -1. Храните состояние как можно локальнее и не [поднимайте его выше](/learn/sharing-state-between-components), чем это действительно необходимо. Не храните переходные состояния типа форм или проверок на hover в библиотеке для управления глобальным состоянием или на самом верху вашего дерева компонентов. -1. Храните ваши компоненты [чистыми](/learn/keeping-components-pure). Если ререндер компонента приводит к проблемам или производит какие-то визуальные артефакты – это баг! Исправьте его, а не прибегайте к мемоизации. +1. Предпочитайте локальное состояние и не [поднимайте его выше](/learn/sharing-state-between-components), чем это действительно необходимо. Не храните переходные состояния типа форм или проверок на hover в библиотеке для управления глобальным состоянием или на самом верху вашего дерева компонентов. +1. Держите ваши компоненты [чистыми](/learn/keeping-components-pure). Если ререндер компонента приводит к проблемам или производит какие-то визуальные артефакты – это баг! Исправьте его, а не прибегайте к мемоизации. 1. Избейгате лишних [Эффектов, которые обновляют состояние](/learn/you-might-not-need-an-effect). В React-приложениях большинство проблем с производительностью вызваны цепочками обновлений, которые создаются в Эффектах и вынуждают компоненты ререндериться снова и снова. 1. Постарайтесь [убрать лишние зависимости в Эффектах](/learn/removing-effect-dependencies). Иногда проще перенести функцию или объект внутрь функции Эффекта, или вынести их за пределы компонента, чем прибегать к мемоизации. @@ -591,7 +591,7 @@ export default function TodoList({ todos, tab, theme }) { } ``` -Подобно тому как объектный литерал `{}` всегда создаёт новый объект, **функция `filterTodos` всегда создаёт новый массив**. Это значит, что компонент `List` всегда будет получать новые пропсы, и оптимизация при помощи [`memo`](/reference/react/memo) не работает. Здесь на помощь приходит `useMemo`: +**В примере ниже функция `filterTodos` всегда создаёт новый массив**, подобно тому как объектный литерал `{}` всегда создаёт новый объект. Это значит, что компонент `List` всегда будет получать новые пропсы, и оптимизация при помощи [`memo`](/reference/react/memo) не работает. Здесь на помощь приходит `useMemo`: ```js {2-3,5,9-10} export default function TodoList({ todos, tab, theme }) { @@ -643,11 +643,11 @@ JSX-узел `` является простым о #### Пропуск ререндеров при помощи `useMemo` и `memo` {/*skipping-re-rendering-with-usememo-and-memo*/} -В данном примере компонент `List` искусственно замедлен, чтобы показать, что случается в том случае, если React-компонент действительно медленный. Попробуйте попереключаться между вкладками и попереключать тему. +В данном примере компонент `List` **искусственно замедлен**, чтобы показать, что случается в том случае, если React-компонент действительно медленный. Попробуйте переключить вкладки и переключить тему. Переключение между вкладками ощущается таким медленным, потому что оно вынуждает замедленный компонент `List` ререндериться. Такое поведение ожидаемо, поскольку проп `tab` изменился, и новые данные необходимо отобразить на экране. -Однако изменение темы (благодаря `useMemo` в связке с [`memo`](/reference/react/memo)) происходит быстро, несмотря на искусственное замедление. Поскольку ни `todos`, ни `tab`, указанные как зависимости в `useMemo`, не изменились с предыдущего рендера, то массив `visibleTodos` остался прежним, и компонент `List` пропустил ререндер. +Затем попробуйте переключить тему. **Благодаря `useMemo` в связке с [`memo`](/reference/react/memo) это происходит быстро, несмотря на искусственное замедление.** Поскольку ни `todos`, ни `tab`, указанные как зависимости в `useMemo`, не изменились с предыдущего рендера, то массив `visibleTodos` остался прежним, и компонент `List` пропустил ререндер. @@ -1066,7 +1066,7 @@ function Dropdown({ allItems, text }) { const visibleItems = useMemo(() => { return searchItems(allItems, searchOptions); - }, [allItems, searchOptions]); // 🚩 Зависимость от объекта, создаваемого внутри компонента + }, [allItems, searchOptions]); // 🚩 Обратите внимание: зависимость от объекта, создаваемого внутри компонента // ... ``` @@ -1182,7 +1182,7 @@ function TodoList({ todos, tab }) { ```js {2-3} const visibleTodos = useMemo(() => { - // 🚩 Внимание: мутация пропса + // 🚩 Ошибка: мутация пропса todos.push({ id: 'last', text: 'Go for a walk!' }); const filtered = filterTodos(todos, tab); return filtered; From 19e0ac16120a8275bcd11d6970af26e750e64495 Mon Sep 17 00:00:00 2001 From: jewhyena <91225197+jewhyena@users.noreply.github.com> Date: Mon, 22 May 2023 11:15:21 +0300 Subject: [PATCH 160/233] Apply suggestions from code review Co-authored-by: Anton Ahatov --- src/content/reference/react/useMemo.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/content/reference/react/useMemo.md b/src/content/reference/react/useMemo.md index ed56b5b92..00c5f56a9 100644 --- a/src/content/reference/react/useMemo.md +++ b/src/content/reference/react/useMemo.md @@ -173,7 +173,7 @@ console.timeEnd('filter array'); Переключение вкладок ощущается таким медленным потому, что оно вынуждает перезапускаться замедленную функцию `filterTodos` каждый раз, когда изменяется значение `tab`. (Если интересно, почему она запускается дважды, объяснение можно найти [здесь](#my-calculation-runs-twice-on-every-re-render).) -**Однако изменение темы, благодаря `useMemo`, происходит быстро (несмотря на искусственное замедление).** Вызов функции `filterTodos` был пропущен потому, что ни `todos`, ни `tab`, указанные как зависимости в `useMemo`, никак не изменились с предыдущего рендера. +Переключите тему. **Благодаря `useMemo` это происходит быстро (несмотря на искусственное замедление).** Медленный вызов `filterTodos` был пропущен, потому что и `todos`, и `tab` (которые вы передаете как зависимости для `useMemo`) не изменились с момента последнего рендера. @@ -303,7 +303,7 @@ label { В данном примере функция `filterTodos` также замедлена, чтобы показать, что случается в том случае, если вызываемая во время рендера функция действительно медленная. Попробуйте попереключаться между вкладками и попереключать тему. -Поскольку в этом примере отсутствует вызов `useMemo`, то искусственно замедленная функция `filterTodos` вызывается при каждом ререндере (даже в том случае, если изменилось только значение `theme`). +Поскольку **в этом примере отсутствует вызов `useMemo`**, то искусственно замедленная функция `filterTodos` вызывается при каждом ререндере (даже в том случае, если изменилось только значение `theme`). @@ -633,7 +633,7 @@ export default function TodoList({ todos, tab, theme }) { JSX-узел `` является простым объектом типа `{ type: List, props: { items: visibleTodos } }`. Создание такого объекта – довольно дешёвая операция, однако React не знает, осталось ли его содержимое прежним или нет. Поэтому по умолчанию React всегда будет ререндерить компонент `List`. -При этом, если React видит тот же JSX, который был при предыдущем рендере, он не будет ререндерить компонент. Так происходит потому, что JSX-узлы являются [неизменяемыми объектами](https://ru.wikipedia.org/wiki/%D0%9D%D0%B5%D0%B8%D0%B7%D0%BC%D0%B5%D0%BD%D1%8F%D0%B5%D0%BC%D1%8B%D0%B9_%D0%BE%D0%B1%D1%8A%D0%B5%D0%BA%D1%82). Такие объекты не могут быть изменены с течением времени, поэтому React знает, что пропустить ререндер – безопасно. Однако чтобы это работало, узел должен быть *буквально тем же объектом*, а не только *выглядеть* таким же в коде. Это именно то, что делает `useMemo` в данном примере. +При этом, если React видит тот же JSX, который был при предыдущем рендере, он не будет ререндерить компонент. Это происходит потому что JSX-узлы [иммутабельны](https://ru.wikipedia.org/wiki/%D0%9D%D0%B5%D0%B8%D0%B7%D0%BC%D0%B5%D0%BD%D1%8F%D0%B5%D0%BC%D1%8B%D0%B9_%D0%BE%D0%B1%D1%8A%D0%B5%D0%BA%D1%82). Такие объекты узлов не могут быть изменены с течением времени, поэтому React знает, что пропустить ререндер безопасно. Однако чтобы это работало, узел должен быть *буквально тем же объектом*, а не только *выглядеть* таким же в коде. Это именно то, что делает `useMemo` в данном примере. Оборачивать JSX-узлы в `useMemo` не всегда удобно. Например, это нельзя делать по условию. По этой причине компоненты чаще оборачивают в [`memo`](/reference/react/memo). From 01241025250920fd614067a2aa43535ab1b35247 Mon Sep 17 00:00:00 2001 From: Konstantin Arabei Date: Mon, 22 May 2023 12:49:53 +0400 Subject: [PATCH 161/233] fix after review --- src/content/learn/your-first-component.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/content/learn/your-first-component.md b/src/content/learn/your-first-component.md index c962c2b63..f4b58b216 100644 --- a/src/content/learn/your-first-component.md +++ b/src/content/learn/your-first-component.md @@ -18,15 +18,15 @@ title: Ваш первый компонент ## Компоненты: строительные блоки UI {/*components-ui-building-blocks*/} -В интернете, HTML позволяет создавать нам структурированные документы, используя встроенный набор тегов, например `

            ` и `
          8. `: +В интернете HTML позволяет создавать нам структурированные документы, используя встроенный набор тегов, например `

            ` и `
          9. `: ```html
            -

            Мой Первый Компонент

            +

            Мой первый компонент

              -
            1. Компоненты: Cтроительные Блоки UI
            2. -
            3. Определение Компонента
            4. -
            5. Использование Компонента
            6. +
            7. Компоненты: строительные блоки UI
            8. +
            9. Определение компонента
            10. +
            11. Использование компонента
            ``` From d4f5be50d8ad85734883bb1733c4f989a0cd1058 Mon Sep 17 00:00:00 2001 From: YashinaAnastasia <83582926+YashinaAnastasia@users.noreply.github.com> Date: Mon, 22 May 2023 12:11:17 +0300 Subject: [PATCH 162/233] Update src/content/reference/react/lazy.md Co-authored-by: Anton Ahatov --- src/content/reference/react/lazy.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/reference/react/lazy.md b/src/content/reference/react/lazy.md index 248285209..b164aa1cc 100644 --- a/src/content/reference/react/lazy.md +++ b/src/content/reference/react/lazy.md @@ -19,7 +19,7 @@ const SomeComponent = lazy(load) ### `lazy(load)` {/*lazy*/} -Чтобы объявить React компонент ленивой загрузки, вызовите `lazy` вне своих компонентов: +Вызовите `lazy` вне ваших компонентов, чтобы объявить компонент React с ленивой загрузкой: ```js import { lazy } from 'react'; From c942ad7d26364da4cd690533a4b71c44c61b7993 Mon Sep 17 00:00:00 2001 From: YashinaAnastasia <83582926+YashinaAnastasia@users.noreply.github.com> Date: Mon, 22 May 2023 12:11:28 +0300 Subject: [PATCH 163/233] Update src/content/reference/react/lazy.md Co-authored-by: Anton Ahatov --- src/content/reference/react/lazy.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/reference/react/lazy.md b/src/content/reference/react/lazy.md index b164aa1cc..4e894a61d 100644 --- a/src/content/reference/react/lazy.md +++ b/src/content/reference/react/lazy.md @@ -31,7 +31,7 @@ const MarkdownPreview = lazy(() => import('./MarkdownPreview.js')); #### Параметры {/*parameters*/} -* `load`: Функция, которая возвращает [Промис](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Promise) или другой *thenable* (объект, в котором определен метод `then`). Вызова `load` не произойдет до тех пор, пока вы не попытайтесь отрендерить возвращённый компонент. После первого вызова `load`, React будет ждать завершения выполнения команды, а затем отрендерит разрешённое значение как React компонент. Возвращённый промис и разрешённое значение Промиса будут кэшированы, `load` больше вызывать не придется. Если промис отклонили, причина этого будет указана в ближайшем Error Boundary. +* `load`: Функция, которая возвращает [Промис](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Promise) или другой *thenable* (объект, в котором определен метод `then`). Вызова `load` не произойдет до тех пор, пока вы не попытаетесь отрендерить возвращённый компонент. После первого вызова `load`, React будет ждать завершения выполнения команды, а затем отрендерит разрешённое значение как React-компонент. Возвращаемый промис и разрешенное значение промиса будут кэшироваться, поэтому React не будет вызывать `load` более одного раза. Если Promise отклоняется, React укажет причину в ближайшем Error Boundary. #### Возвращаемое значение {/*returns*/} From 1f4d2761e7a0c2406a98850650768cb596107ff6 Mon Sep 17 00:00:00 2001 From: YashinaAnastasia <83582926+YashinaAnastasia@users.noreply.github.com> Date: Mon, 22 May 2023 12:11:57 +0300 Subject: [PATCH 164/233] Update src/content/reference/react/lazy.md Co-authored-by: Anton Ahatov --- src/content/reference/react/lazy.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/reference/react/lazy.md b/src/content/reference/react/lazy.md index 4e894a61d..70436132a 100644 --- a/src/content/reference/react/lazy.md +++ b/src/content/reference/react/lazy.md @@ -71,7 +71,7 @@ const MarkdownPreview = lazy(() => import('./MarkdownPreview.js')); Этот код опирается на [динамический `import()`,](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import) который должен поддерживаться вашим бандлером или фреймворком. -Теперь, когда код вашего компонента загружается по запросу, вам также необходимо указать, что должно отображаться во время его загрузки. Это можно сделать путем оборачивания ленивого компонента или его родителя в [``](/reference/react/Suspense) boundary: +Теперь, когда код вашего компонента загружается по запросу, вам также необходимо указать, что должно отображаться во время его загрузки. Это можно сделать путем оборачивания ленивого компонента или его родителя в границы [``](/reference/react/Suspense): ```js {1,4} }> From 3981c451e022aaaa93cc5ed52df5810749d899ce Mon Sep 17 00:00:00 2001 From: YashinaAnastasia <83582926+YashinaAnastasia@users.noreply.github.com> Date: Mon, 22 May 2023 12:13:06 +0300 Subject: [PATCH 165/233] Update src/content/reference/react/lazy.md Co-authored-by: Anton Ahatov --- src/content/reference/react/lazy.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/reference/react/lazy.md b/src/content/reference/react/lazy.md index 70436132a..f1b83828f 100644 --- a/src/content/reference/react/lazy.md +++ b/src/content/reference/react/lazy.md @@ -35,7 +35,7 @@ const MarkdownPreview = lazy(() => import('./MarkdownPreview.js')); #### Возвращаемое значение {/*returns*/} -`lazy` возвращает React компонент, которые можно отрендерить в вашем дереве. Во время загрузки ленивых компонентов попытки их рендера будут *заморожены.* Используйте [``](/reference/react/Suspense) для отображения индикатора во время загрузки. +`lazy` возвращает React-компонент, который можно отрендерить в вашем дереве. Пока код для ленивого компонента все еще загружается, попытка его отрисовки *приостанавливается.* Используйте [``](/reference/react/Suspense) для отображения индикатора загрузки во время загрузки. --- From b41376860f0cf7857f8e4cd5fddd42494738cc1e Mon Sep 17 00:00:00 2001 From: avarlamova <59831804+avarlamova@users.noreply.github.com> Date: Mon, 22 May 2023 12:15:03 +0300 Subject: [PATCH 166/233] Update src/content/learn/importing-and-exporting-components.md Co-authored-by: Anton Ahatov --- src/content/learn/importing-and-exporting-components.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/importing-and-exporting-components.md b/src/content/learn/importing-and-exporting-components.md index a4a721d91..156147591 100644 --- a/src/content/learn/importing-and-exporting-components.md +++ b/src/content/learn/importing-and-exporting-components.md @@ -122,7 +122,7 @@ img { margin: 0 10px 10px 0; height: 90px; } import Gallery from './Gallery'; ``` -Оба варианта (`'./Gallery.js'` и `'./Gallery'`) будут работать в React, хотя первый вариант ближе к тому, как работают [нативные ES-модули](https://developer.mozilla.org/docs/Web/JavaScript/Guide/Modules). +Оба варианта (`'./Gallery.js'` и `'./Gallery'`) будут работать в React, хотя первый вариант ближе к тому, как работают [нативные ES-модули](https://developer.mozilla.org/docs/Web/JavaScript/Guide/Modules). From b57ded1a6b19b79f732783f01d6f7b08f239e376 Mon Sep 17 00:00:00 2001 From: avarlamova <59831804+avarlamova@users.noreply.github.com> Date: Mon, 22 May 2023 12:16:35 +0300 Subject: [PATCH 167/233] fix after review --- src/content/learn/importing-and-exporting-components.md | 1 - 1 file changed, 1 deletion(-) diff --git a/src/content/learn/importing-and-exporting-components.md b/src/content/learn/importing-and-exporting-components.md index a4a721d91..4751e07e8 100644 --- a/src/content/learn/importing-and-exporting-components.md +++ b/src/content/learn/importing-and-exporting-components.md @@ -143,7 +143,6 @@ import Gallery from './Gallery'; При использовании импорта _по умолчанию_ можно использовать любое имя после слова `import`. Например, можно написать `import Banana from './Button.js'`, и эта запись все еще будет корректно импортировать значение по умолчанию. При использовании именованных импортов, напротив, значения должны совпадать в обоих файлах. Именно поэтому такие импорты называются _именованными_. - **Разработчики часто используют экспорт по умолчанию, если файл экспортирует только один компонент, и именованный экспорт, если он экспортирует несколько компонентов и значений.** Независимо от того, какой стиль написания кода вы предпочитаете, всегда давайте осмысленные имена вашим функциональным компонентам и файлам, которые их содержат. Не рекомендуется использовать компоненты без имен, такие как `export default () => {}`, поскольку это затрудняет отладку. From 979c49899f2e0c8eb71bdb8e5462580576d05824 Mon Sep 17 00:00:00 2001 From: jewhyena Date: Mon, 22 May 2023 11:28:13 +0300 Subject: [PATCH 168/233] Apply suggestions from code review --- src/content/reference/react/useMemo.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/content/reference/react/useMemo.md b/src/content/reference/react/useMemo.md index 00c5f56a9..ac8dd4554 100644 --- a/src/content/reference/react/useMemo.md +++ b/src/content/reference/react/useMemo.md @@ -552,7 +552,6 @@ label { В некоторых случаях `useMemo` можно использовать для оптимизации ререндеров дочерних компонентов. Допустим, что `TodoList` передаёт как проп `visibleTodos` дочернему компоненту `List`: - ```js {5} export default function TodoList({ todos, tab, theme }) { // ... @@ -609,7 +608,7 @@ export default function TodoList({ todos, tab, theme }) { } ``` -В примере выше `visibleTodos` всегда будет иметь *одно и то же* значение, пока массив зависимостей остаётся неизменным. Следует помнить, что нет необходимости использовать `useMemo` без веской на то причины. Однако в этом примере `visibleTodos` передаётся как пропс в компонент, обёрнутый в [`memo`](/reference/react/memo), что позволяет пропускать лишние ререндеры. +В примере выше `visibleTodos` всегда будет иметь *одно и то же* значение, пока массив зависимостей остаётся неизменным. Следует помнить, что нет необходимости использовать `useMemo` без веской на то причины. Однако здесь это оправданно, поскольку `visibleTodos` передаётся как пропс в компонент, обёрнутый в [`memo`](/reference/react/memo), что позволяет пропускать лишние ререндеры. Существует ещё несколько причин, когда использование `useMemo` оправданно, – о них речь пойдёт ниже. @@ -631,7 +630,7 @@ export default function TodoList({ todos, tab, theme }) { Поведение будет таким же. Компонент `List` не будет ререндериться, пока значение `visibleTodos` остаётся неизменным. -JSX-узел `` является простым объектом типа `{ type: List, props: { items: visibleTodos } }`. Создание такого объекта – довольно дешёвая операция, однако React не знает, осталось ли его содержимое прежним или нет. Поэтому по умолчанию React всегда будет ререндерить компонент `List`. +JSX-узел `` является простым объектом типа `{ type: List, props: { items: visibleTodos } }`. Создать такой объект очень дёшево, однако React не знает, осталось ли его содержимое прежним или нет. Поэтому по умолчанию React всегда будет ререндерить компонент `List`. При этом, если React видит тот же JSX, который был при предыдущем рендере, он не будет ререндерить компонент. Это происходит потому что JSX-узлы [иммутабельны](https://ru.wikipedia.org/wiki/%D0%9D%D0%B5%D0%B8%D0%B7%D0%BC%D0%B5%D0%BD%D1%8F%D0%B5%D0%BC%D1%8B%D0%B9_%D0%BE%D0%B1%D1%8A%D0%B5%D0%BA%D1%82). Такие объекты узлов не могут быть изменены с течением времени, поэтому React знает, что пропустить ререндер безопасно. Однако чтобы это работало, узел должен быть *буквально тем же объектом*, а не только *выглядеть* таким же в коде. Это именно то, что делает `useMemo` в данном примере. From 703b7d79d36624e899063bb3c8ad078d224d4fce Mon Sep 17 00:00:00 2001 From: Laroikin <48063190+Laroikin@users.noreply.github.com> Date: Mon, 22 May 2023 20:27:34 +0900 Subject: [PATCH 169/233] Update src/content/learn/rendering-lists.md Co-authored-by: Anton Ahatov --- src/content/learn/rendering-lists.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/rendering-lists.md b/src/content/learn/rendering-lists.md index 73bcb8d9f..2f48bf59a 100644 --- a/src/content/learn/rendering-lists.md +++ b/src/content/learn/rendering-lists.md @@ -12,7 +12,7 @@ title: Рендер списков * Как рендерить компоненты из массива, используя `map()` * Как рендерить только определенные компоненты, используя `filter()` -* Когда и зачем использовать React ключи +* Когда и зачем использовать React-ключи From 7e6acd05bbc3f21733c5569c35366c2299a9dfe6 Mon Sep 17 00:00:00 2001 From: Laroikin <48063190+Laroikin@users.noreply.github.com> Date: Mon, 22 May 2023 20:27:43 +0900 Subject: [PATCH 170/233] Update src/content/learn/rendering-lists.md Co-authored-by: Anton Ahatov --- src/content/learn/rendering-lists.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/rendering-lists.md b/src/content/learn/rendering-lists.md index 2f48bf59a..7c7a91f8d 100644 --- a/src/content/learn/rendering-lists.md +++ b/src/content/learn/rendering-lists.md @@ -283,7 +283,7 @@ Warning: Each child in a list should have a unique "key" prop. -JSX элементы, созданные внутри `map()` всегда должны иметь ключи! +JSX-элементы, созданные внутри `map()` всегда должны иметь ключи! From f6c05a906b02c912f3fb49c73d8c84cb5124dad3 Mon Sep 17 00:00:00 2001 From: Laroikin <48063190+Laroikin@users.noreply.github.com> Date: Mon, 22 May 2023 20:27:52 +0900 Subject: [PATCH 171/233] Update src/content/learn/rendering-lists.md Co-authored-by: Anton Ahatov --- src/content/learn/rendering-lists.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/rendering-lists.md b/src/content/learn/rendering-lists.md index 7c7a91f8d..0c737da73 100644 --- a/src/content/learn/rendering-lists.md +++ b/src/content/learn/rendering-lists.md @@ -377,7 +377,7 @@ img { width: 100px; height: 100px; border-radius: 50%; } #### Отображение нескольких DOM узлов для каждого элемента списка {/*displaying-several-dom-nodes-for-each-list-item*/} -Как поступить, если каждый элемент должен отображать не один, а несколько DOM узлов? +Как поступить, если каждый элемент должен отображать не один, а несколько DOM-узлов? Краткий синтаксис [`<>...` фрагмента](/reference/react/Fragment) не позволяет передавать ключ, поэтому нужно либо объединить их в один `
            `, либо использовать чуть более длинный и [более явный ``:](/reference/react/Fragment#rendering-a-list-of-fragments) From 6c678e0a08605d1167b25179d2f0831a6a9d65fc Mon Sep 17 00:00:00 2001 From: Laroikin <48063190+Laroikin@users.noreply.github.com> Date: Mon, 22 May 2023 20:28:05 +0900 Subject: [PATCH 172/233] Update src/content/learn/rendering-lists.md Co-authored-by: Anton Ahatov --- src/content/learn/rendering-lists.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/rendering-lists.md b/src/content/learn/rendering-lists.md index 0c737da73..d8a7c6783 100644 --- a/src/content/learn/rendering-lists.md +++ b/src/content/learn/rendering-lists.md @@ -375,7 +375,7 @@ img { width: 100px; height: 100px; border-radius: 50%; } -#### Отображение нескольких DOM узлов для каждого элемента списка {/*displaying-several-dom-nodes-for-each-list-item*/} +#### Отображение нескольких DOM-узлов для каждого элемента списка {/*displaying-several-dom-nodes-for-each-list-item*/} Как поступить, если каждый элемент должен отображать не один, а несколько DOM-узлов? From b2e58e3d20203fa33ea8228094491fb6f3ac4c69 Mon Sep 17 00:00:00 2001 From: Laroikin <48063190+Laroikin@users.noreply.github.com> Date: Mon, 22 May 2023 20:28:13 +0900 Subject: [PATCH 173/233] Update src/content/learn/rendering-lists.md Co-authored-by: Anton Ahatov --- src/content/learn/rendering-lists.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/rendering-lists.md b/src/content/learn/rendering-lists.md index d8a7c6783..b68c2367e 100644 --- a/src/content/learn/rendering-lists.md +++ b/src/content/learn/rendering-lists.md @@ -980,7 +980,7 @@ export const recipes = [{ #### Извлечение компонента элемента списка {/*extracting-a-list-item-component*/} -Компонент `RecipeList` содержит два вложенных вызова map. Чтобы упростить его, извлеките компонент `Recipe`, который будет принимать пропсы `id`, `name` и `ingredients`. Где вы разместите внешний `key` и почему? +Компонент `RecipeList` содержит два вложенных вызова `map`. Чтобы упростить его, извлеките компонент `Recipe`, который будет принимать пропсы `id`, `name` и `ingredients`. Где вы разместите внешний `key` и почему? From 039569823a9cfd623d0a52bf1617b55125fd378d Mon Sep 17 00:00:00 2001 From: Laroikin Date: Mon, 22 May 2023 20:29:22 +0900 Subject: [PATCH 174/233] fix: remove empty line at the end of file --- src/content/learn/rendering-lists.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/rendering-lists.md b/src/content/learn/rendering-lists.md index b68c2367e..01550501a 100644 --- a/src/content/learn/rendering-lists.md +++ b/src/content/learn/rendering-lists.md @@ -1261,4 +1261,4 @@ hr { - + \ No newline at end of file From 2a91171a305106ac99ba70da82df9472736ea6d8 Mon Sep 17 00:00:00 2001 From: Laroikin Date: Mon, 22 May 2023 20:30:34 +0900 Subject: [PATCH 175/233] fix: remove empty line at line 1031 --- src/content/learn/rendering-lists.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/content/learn/rendering-lists.md b/src/content/learn/rendering-lists.md index 01550501a..99e09d624 100644 --- a/src/content/learn/rendering-lists.md +++ b/src/content/learn/rendering-lists.md @@ -1028,7 +1028,6 @@ export const recipes = [{ - Вы можете скопировать и вставить JSX из внешнего вызова map в новый компонент `Recipe` и вернуть этот JSX. Затем вы можете изменить `recipe.name` на `name`, `recipe.id` на `id` и т.д., и передать их в виде пропсов компоненту `Recipe`: @@ -1261,4 +1260,4 @@ hr { - \ No newline at end of file + From 808eee34d8dabdab1ef9faa8281e15de437bdbe5 Mon Sep 17 00:00:00 2001 From: Viacheslav Makarov <9768704+mekarthedev@users.noreply.github.com> Date: Mon, 22 May 2023 14:19:36 +0200 Subject: [PATCH 176/233] Apply suggestions from code review Co-authored-by: Anton Ahatov --- src/content/reference/react/useDeferredValue.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/content/reference/react/useDeferredValue.md b/src/content/reference/react/useDeferredValue.md index 9d0caa2fb..f23bd37c7 100644 --- a/src/content/reference/react/useDeferredValue.md +++ b/src/content/reference/react/useDeferredValue.md @@ -36,7 +36,7 @@ function SearchPage() { #### Параметры {/*parameters*/} -* `value`: Значение, обновление которого вы хотите откладывать. +* `value`: Значение, обновление которого вы хотите отложить. #### Возвращаемое значение {/*returns*/} @@ -945,9 +945,9 @@ export default SlowList; Возможно, вы в похожей ситуации применили бы один из двух распространённых приёмов: - *Дебаунсинг (debouncing)*, при котором приложение сначала бы дожидалось, когда пользователь перестанет печатать (уже секунду не печатал, например), и потом обновляло список. -- *Тротлинг (throttling)*, при котором, как бы быстро пользователь не печатал, приложение обновляло бы список не чаще одного раза за какой-то период (раз в секунду, например). +- *Тротлинг (throttling)*, при котором, как бы быстро пользователь ни печатал, приложение обновляло бы список не чаще одного раза за какой-то период (раз в секунду, например). -Это отличные и часто очень полезные техники. Но `useDeferredValue` лучше подходит для оптимизации рендеринга потому, что он, тесно взаимодействуя с React, может подстраиваться под возможности устройства пользователя. +Хотя эти методы полезны в некоторых случаях, `useDeferredValue` лучше подходит для оптимизации рендеринга, поскольку он тесно взаимодействует с React и может подстроиться под возможности устройства пользователя. Можно не привязываться к какой-то фиксированной задержке. У пользователей с быстрым, мощным устройством фоновый рендеринг будет выполняться быстро и без заметной задержки. А у пользователей со слабым устройством список будет "отставать" ровно на столько, на сколько позволяет устройство. From a5dbf0c92602b126468b3fc3150631bc91c4fbe6 Mon Sep 17 00:00:00 2001 From: TibidoX <79273248+TibidoX@users.noreply.github.com> Date: Mon, 22 May 2023 16:38:16 +0300 Subject: [PATCH 177/233] Update src/content/reference/react-dom/server/renderToString.md Co-authored-by: Anton Ahatov --- src/content/reference/react-dom/server/renderToString.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/reference/react-dom/server/renderToString.md b/src/content/reference/react-dom/server/renderToString.md index cd3187900..bc73d7fb7 100644 --- a/src/content/reference/react-dom/server/renderToString.md +++ b/src/content/reference/react-dom/server/renderToString.md @@ -1,5 +1,5 @@ --- -Заголовок: renderToString +title: renderToString --- From 478ee85c575ab11295cc04d4d33ed0ea59a146fe Mon Sep 17 00:00:00 2001 From: Konstantin Arabei Date: Mon, 22 May 2023 17:58:38 +0400 Subject: [PATCH 178/233] remove translation from .tsx files --- src/components/MDX/Challenges/Challenge.tsx | 8 ++++---- src/components/MDX/ExpandableCallout.tsx | 2 +- src/components/MDX/ExpandableExample.tsx | 2 +- src/components/MDX/MDXComponents.tsx | 2 +- src/components/MDX/Recap.tsx | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/components/MDX/Challenges/Challenge.tsx b/src/components/MDX/Challenges/Challenge.tsx index b66d5a99b..24e99541c 100644 --- a/src/components/MDX/Challenges/Challenge.tsx +++ b/src/components/MDX/Challenges/Challenge.tsx @@ -63,14 +63,14 @@ export function Challenge({
            ) : ( @@ -80,7 +80,7 @@ export function Challenge({ onClick={toggleSolution} active={showSolution}> {' '} - {showSolution ? 'Скрыть решение' : 'Показать решение'} + {showSolution ? 'Hide solution' : 'Show solution'} ) )} @@ -109,7 +109,7 @@ export function Challenge({ {currentChallenge.solution}
            {hasNextChallenge && (
            {children}; } diff --git a/src/components/MDX/Recap.tsx b/src/components/MDX/Recap.tsx index f37c85f17..d91ed48b4 100644 --- a/src/components/MDX/Recap.tsx +++ b/src/components/MDX/Recap.tsx @@ -13,7 +13,7 @@ function Recap({children}: RecapProps) { return (

            - Итого + Recap

            {children}
            From 765c9f6274641c0ec31209de71059fb1adfa6bd1 Mon Sep 17 00:00:00 2001 From: Daniil Bederdinov <36964844+Palidos@users.noreply.github.com> Date: Mon, 22 May 2023 19:51:40 +0300 Subject: [PATCH 179/233] Add suggestion Co-authored-by: Anton Ahatov --- src/content/learn/installation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/installation.md b/src/content/learn/installation.md index 102f394f8..1f853bd9d 100644 --- a/src/content/learn/installation.md +++ b/src/content/learn/installation.md @@ -19,7 +19,7 @@ React был спроектирован с самого начала с учёт ## Попробовать React {/*try-react*/} -Чтобы попробовать React, даже устанавливать ничего не нужно. Поредактируйте код в песочнице! +Вам не нужно ничего устанавливать, чтобы попробовать React. Поредактируйте код в песочнице! From a0ee218c86997a4ce22b6bc1d554e6643e9f4136 Mon Sep 17 00:00:00 2001 From: Daniil Bederdinov <36964844+Palidos@users.noreply.github.com> Date: Mon, 22 May 2023 23:02:18 +0300 Subject: [PATCH 180/233] Add suggestion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "для ознакомления с самыми важными концепциями" --- src/content/learn/installation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/installation.md b/src/content/learn/installation.md index 1f853bd9d..9884a65f2 100644 --- a/src/content/learn/installation.md +++ b/src/content/learn/installation.md @@ -53,5 +53,5 @@ export default function App() { ## Дальнейшие шаги {/*next-steps*/} -Перейдите к [Введению в React](/learn) чтобы ознакомиться с его важнейшими концепциями, которые вы будете встречать каждый день. +Перейдите к [Введению в React](/learn) для ознакомления с самыми важными концепциями, которые вы будете встречать каждый день. From 47fff652f559a9fd66adfc40479f0dc734446c47 Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Mon, 22 May 2023 23:22:27 +0300 Subject: [PATCH 181/233] Update src/content/learn/conditional-rendering.md Co-authored-by: Nick Tishkevich --- src/content/learn/conditional-rendering.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/conditional-rendering.md b/src/content/learn/conditional-rendering.md index 97f0594e3..658cd7ef5 100644 --- a/src/content/learn/conditional-rendering.md +++ b/src/content/learn/conditional-rendering.md @@ -10,7 +10,7 @@ title: Условный рендеринг -- Как вернуть разный JSX, в зависимости от ситуации. +- Как вернуть разный JSX, в зависимости от условия. - Как по условию добавить или убрать часть JSX. - Часто встречающиеся конструкции, которые вы найдете в проектах на React. From 7fc6784e1497d853eaffb95549d6deb7e02186b4 Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Mon, 22 May 2023 23:23:46 +0300 Subject: [PATCH 182/233] Update src/content/learn/conditional-rendering.md Co-authored-by: Nick Tishkevich --- src/content/learn/conditional-rendering.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/conditional-rendering.md b/src/content/learn/conditional-rendering.md index 658cd7ef5..b5c5c2857 100644 --- a/src/content/learn/conditional-rendering.md +++ b/src/content/learn/conditional-rendering.md @@ -11,7 +11,7 @@ title: Условный рендеринг - Как вернуть разный JSX, в зависимости от условия. -- Как по условию добавить или убрать часть JSX. +- Как в зависимости от условий добавить или убрать часть JSX. - Часто встречающиеся конструкции, которые вы найдете в проектах на React. From 7ea68e11a4f5fec36c810b050528b06e5e327df5 Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Mon, 22 May 2023 23:36:18 +0300 Subject: [PATCH 183/233] Apply suggestions from code review Co-authored-by: Nick Tishkevich --- src/content/learn/conditional-rendering.md | 74 +++++++++++----------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/src/content/learn/conditional-rendering.md b/src/content/learn/conditional-rendering.md index b5c5c2857..dd4d3fb19 100644 --- a/src/content/learn/conditional-rendering.md +++ b/src/content/learn/conditional-rendering.md @@ -12,13 +12,13 @@ title: Условный рендеринг - Как вернуть разный JSX, в зависимости от условия. - Как в зависимости от условий добавить или убрать часть JSX. -- Часто встречающиеся конструкции, которые вы найдете в проектах на React. +- Часто встречающиеся сокращения синтаксиса условных выражений, с которыми вы столкнётесь в проектах на React. ## Условно возвращаемый JSX {/*conditionally-returning-jsx*/} -Допустим, у вас есть компонент `PackingList`, который рендерит несколько компонентов `Item`, они могут быть обозначены, как упакованные или нет: +Допустим, у вас есть компонент `PackingList`, который рендерит несколько компонентов `Item`, который могут быть отмечены как упакованные или нет: @@ -52,7 +52,7 @@ export default function PackingList() { -Обратите внимание, что некоторые компоненты `Item` имеют свойство `isPacked`, со значением `true` вместо `false`. Допустим, вы хотите добавить (✔) к упакованным вещам, если if `isPacked={true}`. +Обратите внимание, что у некоторых компонентов `Item` установлено свойство `isPacked` в значение `true`, вместо значения `false`. Если `isPacked={true}`, вы хотите добавить галочку(✔) к упакованным вещам. Можно реализовать это с помощью [управляющей конструкции `if`/`else`](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Statements/if...) таким образом: @@ -63,7 +63,7 @@ if (isPacked) { return
          10. {name}
          11. ; ``` -Если `isPacked` проп — это `true`, то этот код **вернёт другое JSX дерево.** Вместе с этим изменением, некоторые вещи получат галочку в конце: +Если `isPacked` проп равен `true`, то этот код **вернёт другое JSX дерево.** Вместе с этим изменением, некоторые вещи получат галочку в конце: @@ -102,7 +102,7 @@ export default function PackingList() { Попробуйте отредактировать то, что возвращается в обоих случаях, и посмотрите, как изменится результат! -Обратите внимание, как вы создаете разветвленную логику с помощью операторов JavaScript `if` и `return`. В React поток управления (как и условия) обрабатывается JavaScript. +Обратите внимание, как вы создаёте разветвлённую логику с помощью операторов JavaScript `if` и `return`. В React управление потоком выполнения (например, условия) обрабатывает JavaScript. ### Условно возвращаем ничего, с помощью `null` {/*conditionally-returning-nothing-with-null*/} @@ -115,7 +115,7 @@ if (isPacked) { return
          12. {name}
          13. ; ``` -Если `isPacked` true, то компонент не вернет ничего, `null`. В противном случае он вернет JSX для рендеринга. +Если `isPacked` равен true, то компонент не вернёт ничего, `null`. В противном случае, он вернёт JSX для рендеринга. @@ -152,7 +152,7 @@ export default function PackingList() { -На практике возврат `null` из компонента не является обычным делом, поскольку это может удивить разработчика, пытающегося его зарендерить. Чаще всего вы условно включаете или исключаете компонент JSX из родительского компонента. Вот как это сделать! +На практике возврат `null` из компонента не является обычным делом, поскольку это может удивить разработчика, пытающегося его рендерить. Чаще всего вы будете условно включать или исключать компонент в JSX родительского компонента. Вот как это сделать! ## Условное включение JSX {/*conditionally-including-jsx*/} @@ -168,7 +168,7 @@ export default function PackingList() {
          14. {name}
          15. ``` -Обе условные ветви возвращают `
          16. ...
          17. `: +Обе ветки условия возвращают `
          18. ...
          19. `: ```js if (isPacked) { @@ -177,11 +177,11 @@ if (isPacked) { return
          20. {name}
          21. ; ``` -Хоть и такое дублирование не вредно, но оно может усложнить поддержание вашего кода. Что если вы захотите изменить `className`? Вам придется делать это в двух местах вашего кода! В такой ситуации вы можете условно включить небольшой JSX, чтобы сделать ваш код более [DRY.](https://ru.wikipedia.org/wiki/Don%E2%80%99t_repeat_yourself). +Хоть и такое дублирование не вредно, но оно может усложнить поддержку вашего кода. Что если вы захотите изменить `className`? Вам придётся делать это в двух местах вашего кода! В такой ситуации вы можете условно включить небольшой JSX, чтобы сделать ваш код более [DRY.](https://ru.wikipedia.org/wiki/Don%E2%80%99t_repeat_yourself). ### Условный (тернанрый) оператор (`? :`) {/*conditional-ternary-operator--*/} -В JavaScript есть компактный синтаксис для написания условного выражения — [условный оператор](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Operators/Conditional_Operator) или "тернарный оператор". +В JavaScript есть компактный синтаксис для записи условного выражения — [условный оператор](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Operators/Conditional_Operator) или "тернарный оператор". Вместо этого: @@ -202,13 +202,13 @@ return ( ); ``` -Вы можете читать это как *"if `isPacked` это true, тогда (`?`) рендерим `name + ' ✔'`, в противном случае (`:`) рендерю `name`"*. +Вы можете читать это как *"if `isPacked` равно true, тогда (`?`) рендерим `name + ' ✔'`, в противном случае (`:`) рендерим `name`"*. #### Являются ли эти два примера полностью эквивалентными? {/*are-these-two-examples-fully-equivalent*/} -Если вы знакомы с объектно-ориентированным программированием, вы можете предположить, что два приведенных выше примера мало чем отличаются друг от друга, поскольку один из них может создавать два разных "экземпляра" `
          22. `. Но элементы JSX не являются "экземплярами", потому что они не хранят никакого внутреннего состояния и не являются реальными узлами DOM. Это легкие описания, как чертежи. Так что эти два примера, на самом деле, *совершенно эквивалентны*. В [Сохранение и сброс состояния](/learn/preserving-and-resetting-state) подробно рассказывается о том, как это работает. +Если вы знакомы с объектно-ориентированным программированием, вы можете предположить, что два приведенных выше примера немного отличаются друг от друга, поскольку один из них может создавать два разных "экземпляра" `
          23. `. Но JSX-элементы не являются "экземплярами", потому что они не хранят никакого внутреннего состояния и не являются реальными DOM-узлами . Это лёгкие описания, как чертежи. На самом деле эти два примера *совершенно эквивалентны*. В [Сохранение и сброс состояния](/learn/preserving-and-resetting-state) подробно рассказывается о том, как это работает. @@ -256,9 +256,9 @@ export default function PackingList() { -Этот стиль хорошо работает для простых условий, но используйте его в меру. Если ваши компоненты становятся беспорядочными из-за слишком большого количества вложенной условной разметки, подумайте об извлечении дочерних компонентов, чтобы навести порядок. В React разметка является частью кода, поэтому вы можете использовать такие инструменты, как переменные и функции, чтобы привести в порядок сложные выражения. +Этот стиль хорошо работает для простых условий, но используйте его в меру. Если ваши компоненты становятся запутанными из-за слишком большого количества вложенной условной разметки, подумайте об выделении дочерних компонентов, чтобы навести порядок. В React разметка является частью кода, поэтому вы можете использовать такие инструменты, как переменные и функции, чтобы привести в порядок сложные выражения. -### Логичксий И оператор (`&&`) {/*logical-and-operator-*/} +### Логический оператор И(`&&`) {/*logical-and-operator-*/} Еще одно часто встречающееся сокращение [JavaScript логический И (`&&`) оператор.](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Operators/Logical_AND) Внутри React компонентов, часто случается так, что тебе нужно зарендерить JSX, когда условие true, **или не рендерить ничего.** С `&&`, вы можете исходя из условия зарендерить галочку, if `isPacked` это `true`: @@ -270,7 +270,7 @@ return ( ); ``` -Вы можете читать это как *"if `isPacked`, тогда (`&&`) рендерим галочку, в противном случае, мы не рендерим ничего"*. +Вы можете читать это как *"если `isPacked`, тогда (`&&`) рендерим галочку, в противном случае -- ничего не рендерим"*. Вот это в действии: @@ -310,30 +310,30 @@ export default function PackingList() { -[JavaScript && выражение](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Operators/Logical_AND) возвращает значение его правой стороны (в нашем случае это галочка) на левой стороне (наше условие) это `true`. Но если наше условие — `false`, тогда всё выражение становится `false`. React думает о `false` как о "дыре" внутри JSX дерева, прямо как о `null` или `undefined`, и React не рендерит ничего на этом месте. +[JavaScript выражение &&](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Operators/Logical_AND) возвращает значение правой части (в нашем случае это галочка), если левая часть (наше условие) является `true`. Но если наше условие — `false`, тогда всё выражение становится `false`. React рассматривает `false` как "пустое место" в дереве JSX, прямо как `null` или `undefined`, и ничего не рендерит на этом месте. **Не ставь числа по левую сторону `&&`.** -Чтобы проверить условие, JavaScript автоматически преобразует левую часть в булевое значение (true/false). Однако если левая часть равна `0`, то все выражение получает это значение (`0`), и React с радостью зарендерит `0`, а не ничего. +Для проверки условия JavaScript автоматически преобразует левую часть в булевое значение. Однако, если левая часть равна `0`, то всё выражение получает это значение (`0`), и React будет с радостью рендерить `0` вместо ничего. -Например, распространенной ошибкой является написание кода типа `messageCount &&

            New messages

            `. Легко предположить, что он ничего не рендерит, когда `messageCount` равно `0`, но на самом деле он зарендерит `0`! +Например, распространённой ошибкой является написание кода вида `messageCount &&

            Новые сообщения

            `. Легко предположить, что ничего не отрендерено, когда `messageCount` равно `0`, но на самом деле будет рендериться `0`! -Чтобы исправить это, сделайте левую часть булевым значением (true/false): `messageCount > 0 &&

            New messages

            `. +Чтобы исправить это, сделайте левую часть булевым значением: `messageCount > 0 &&

            Новые сообщения

            `.
            ### Условное присвоение JSX к переменной {/*conditionally-assigning-jsx-to-a-variable*/} -Когда сокращения встревают на пути к написанию понятного кода, то попробуйте использовать `if` оператор и переменную. Вы можете изменить переменные, написанные с помощью [`let`](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Statements/let), поэтому начните с предоставления содержимого по умолчанию, которое вы хотите отобразить, name: +Когда сокращения мешают написанию понятного кода, то попробуйте использовать `if` оператор и переменную. Вы можете переназначать переменные, объявленные с помощью [`let`](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Statements/let), поэтому начните с предоставления содержимого по умолчанию, которое вы хотите отобразить, например, name: ```js let itemContent = name; ``` -Используйте `if` оператор чтобы переназначить JSX выражение `itemContent` если `isPacked` это `true`: +Используйте `if` оператор, чтобы переназначить JSX-выражение `itemContent`, если `isPacked` равно `true`: ```js if (isPacked) { @@ -437,16 +437,16 @@ export default function PackingList() { -Если вы не знакомы с JavaScript, то такое разнообразие стилей может показаться поначалу ошеломляющим. Однако их изучение поможет вам читать и писать любой код JavaScript — и не только компоненты React! Выберите для начала тот, который вам больше нравится, а затем снова обратитесь к этому справочнику, если вы забудете, как работают другие. +Если вы не знакомы с JavaScript, то такое разнообразие стилей может показаться поначалу ошеломляющим. Однако их изучение поможет вам читать и писать любой JavaScript код, а не только React-компоненты! Выберите тот, который вам больше нравится, и при необходимости обратитесь к этому справочнику, если вы забудете, как работают другие. - В React вы управляете логикой ветвления с помощью JavaScript. -- Вы можете возвращать выражение JSX условно с помощью оператора `if`. -- Вы можете условно сохранить логику JSX в переменную, а затем включить её в другие JSX с помощью фигурных скобок. -- В JSX, `{cond ? : }` означает *"if `cond`, рендери ``, в противном случае ``"*. -- В JSX, `{cond && }` означает *"if `cond`, рендери ``, иначе ничего"*. -- Эти сокращения являются общепринятыми, но вы не обязаны их использовать, если предпочитаете простые выражения. `if`. +- Вы можете условно возвращать JSX-выражение с помощью оператора `if`. +- Вы можете условно сохранить JSX в переменную и затем включить её в другой JSX с помощью фигурных скобок. +- В JSX выражение `{cond ? : }` означает *"если `cond`, то отрендерить ``, иначе ``"*. +- В JSX выражение `{cond && }` означает *"если `cond`, то отрендерить``, иначе ничего"*. +- Эти сокращения являются общепринятыми, но эти сокращения необязательно использовать, если вы предпочитаете простой `if`. @@ -454,9 +454,9 @@ export default function PackingList() { -#### Покажи иконку для неупакованных вещей с `? :` {/*show-an-icon-for-incomplete-items-with--*/} +#### Показать иконку для неупакованных вещей с `? :` {/*show-an-icon-for-incomplete-items-with--*/} -Используй тернарный оператор (`cond ? a : b`) чтобы зарендерить ❌ if `isPacked` не равен `true`. +Используйте тернарный оператор (`cond ? a : b`), чтобы отрендерить❌, если `isPacked` не равен `true`. @@ -534,7 +534,7 @@ export default function PackingList() { -#### Покажи важность вещи с помощью `&&` {/*show-the-item-importance-with-*/} +#### Показать важность вещи с помощью `&&` {/*show-the-item-importance-with-*/} В этом примере каждый `Item` получает числовой `importance` проп. Используй `&&` чтобы зарендерить "_(Важность: X)_" в italics стиле, но только для вещей важность которых больше 0. Ваш конечный резульат должен выглядеть вот так вот: @@ -624,15 +624,15 @@ export default function PackingList() { -Помните, что вы должны писать `importance > 0 && ...` а не `importance && ...` и если `importance` это `0`, то `0` не зарендерится как результат! +Помните, что вы должны писать `importance > 0 && ...` вместо `importance && ...`, чтобы при `importance` равном `0` число `0` не рендерилось в результате! -В этом решении, два раздельных условия были использованы, чтобы вставить пробел между именем и меткой важности. В качестве альтернативы можно использовать фрагмент с ведущим пробелом: `importance > 0 && <> ...` или добавить пробел сразу внутри тега ``: `importance > 0 && ...`. +В этом решении используются два отдельных условия для вставки пробела между именем и меткой важности. Кроме того, можно использовать фрагмент с ведущим пробелом: `importance > 0 && <> ...` или добавить пробел сразу внутри тега ``: `importance > 0 && ...`. -#### Перепешите тернарный оператор `? :` на `if` с переменной {/*refactor-a-series-of---to-if-and-variables*/} +#### Перепишите тернарный оператор `? :` на `if` и переменные {/*refactor-a-series-of---to-if-and-variables*/} -Этот `Drink` компонент использует серию `? :` условий, чтобы показать разную информацию, которая зависит от `name` пропа, который `"tea"` или `"coffee"`. Проблема в том, что информация о каждом напитке распределена по нескольким условиям. Перепешите этот код так, чтобы использовать одно `if` условие вместо трёх `? :` условий. +Компонент `Drink` использует серию условий `? :` для отображения разной информацию в зависимости от пропа `name` (может быть `"tea"` или `"coffee"`). Проблема заключается в том, что информация о каждом напитке разбросана по нескольким условиям. Перепишите этот код так, используя один `if` вместо трёх условий `? :`. @@ -665,7 +665,7 @@ export default function DrinkList() { -После рефакторинга кода с использованием `if` у вас есть идеи, как его упростить? +После рефакторинга кода с использованием `if`, у вас есть ещё идеи о том, как упростить его? @@ -712,9 +712,9 @@ export default function DrinkList() { -Здесь информация о каждом напитке сгруппирована вместе, а не распределена по нескольким условиям. Это облегчает добавление новых напитков в будущем. +Здесь информация о каждом напитке сгруппирована вместе, а не разбросана по нескольким условиям. Это облегчает добавление новых напитков в будущем. -Другим решением может быть полное удаление условий путем перемещения информации в объекты: +Другим решением будет удалить условия, переместив информацию в объекты: From 5418784c9a3f9d81b6e5c7f094464e0e667c2658 Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Mon, 22 May 2023 23:49:00 +0300 Subject: [PATCH 184/233] Update conditional-rendering.md --- src/content/learn/conditional-rendering.md | 44 +++++++++++----------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/content/learn/conditional-rendering.md b/src/content/learn/conditional-rendering.md index dd4d3fb19..721f8ef5d 100644 --- a/src/content/learn/conditional-rendering.md +++ b/src/content/learn/conditional-rendering.md @@ -265,7 +265,7 @@ export default function PackingList() { ```js return (
          24. - {name} {isPacked && "✔"} + {name} {isPacked && '✔'}
          25. ); ``` @@ -280,7 +280,7 @@ return ( function Item({ name, isPacked }) { return (
          26. - {name} {isPacked && "✔"} + {name} {isPacked && '✔'}
          27. ); } @@ -337,7 +337,7 @@ let itemContent = name; ```js if (isPacked) { - itemContent = name + " ✔"; + itemContent = name + ' ✔'; } ``` @@ -357,7 +357,7 @@ if (isPacked) { function Item({ name, isPacked }) { let itemContent = name; if (isPacked) { - itemContent = name + " ✔"; + itemContent = name + ' ✔'; } return (
          28. @@ -464,7 +464,7 @@ export default function PackingList() { function Item({ name, isPacked }) { return (
          29. - {name} {isPacked && "✔"} + {name} {isPacked && '✔'}
          30. ); } @@ -502,7 +502,7 @@ export default function PackingList() { function Item({ name, isPacked }) { return (
          31. - {name} {isPacked ? "✔" : "❌"} + {name} {isPacked ? '✔' : '❌'}
          32. ); } @@ -643,11 +643,11 @@ function Drink({ name }) {

            {name}

            Часть растения
            -
            {name === "tea" ? "leaf" : "bean"}
            +
            {name === 'tea' ? 'leaf' : 'bean'}
            Содержание кофеина
            -
            {name === "tea" ? "15–70 мг/чашка" : "80–185 мг/чашка"}
            +
            {name === 'tea' ? '15–70 мг/чашка' : '80–185 мг/чашка'}
            Возраст
            -
            {name === "tea" ? "4,000+ лет" : "1,000+ лет"}
            +
            {name === 'tea' ? '4,000+ лет' : '1,000+ лет'}

      3. ); @@ -676,14 +676,14 @@ export default function DrinkList() { ```js function Drink({ name }) { let part, caffeine, age; - if (name === "tea") { - part = "leaf"; - caffeine = "15–70 мг/чашка"; - age = "4,000+ лет"; - } else if (name === "coffee") { - part = "bean"; - caffeine = "80–185 мг/чашка"; - age = "1,000+ лет"; + if (name === 'tea') { + part = 'leaf'; + caffeine = '15–70 мг/чашка'; + age = '4,000+ лет'; + } else if (name === 'coffee') { + part = 'bean'; + caffeine = '80–185 мг/чашка'; + age = '1,000+ лет'; } return (
        @@ -721,14 +721,14 @@ export default function DrinkList() { ```js const drinks = { tea: { - part: "leaf", - caffeine: "15–70 мг/чашка", + part: 'leaf', + caffeine: '15–70 мг/чашка', age: "4,000+ лет", }, coffee: { - part: "bean", - caffeine: "80–185 мг/чашка", - age: "1,000+ лет", + part: 'bean', + caffeine: '80–185 мг/чашка', + age: '1,000+ лет', }, }; From b6a4b366fd2e67d12911cebf9f8dca3585b3ef91 Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Mon, 22 May 2023 23:49:45 +0300 Subject: [PATCH 185/233] Update src/content/learn/conditional-rendering.md Co-authored-by: Nick Tishkevich --- src/content/learn/conditional-rendering.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/conditional-rendering.md b/src/content/learn/conditional-rendering.md index 721f8ef5d..ecae73e38 100644 --- a/src/content/learn/conditional-rendering.md +++ b/src/content/learn/conditional-rendering.md @@ -206,7 +206,7 @@ return ( -#### Являются ли эти два примера полностью эквивалентными? {/*are-these-two-examples-fully-equivalent*/} +#### Эти два примера полностью эквивалентны? {/*are-these-two-examples-fully-equivalent*/} Если вы знакомы с объектно-ориентированным программированием, вы можете предположить, что два приведенных выше примера немного отличаются друг от друга, поскольку один из них может создавать два разных "экземпляра" `
      4. `. Но JSX-элементы не являются "экземплярами", потому что они не хранят никакого внутреннего состояния и не являются реальными DOM-узлами . Это лёгкие описания, как чертежи. На самом деле эти два примера *совершенно эквивалентны*. В [Сохранение и сброс состояния](/learn/preserving-and-resetting-state) подробно рассказывается о том, как это работает. From 75e6c33b0612317f924ebab6e6eddf3b9879202e Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Tue, 23 May 2023 00:00:13 +0300 Subject: [PATCH 186/233] Update src/content/learn/conditional-rendering.md Co-authored-by: Nick Tishkevich --- src/content/learn/conditional-rendering.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/conditional-rendering.md b/src/content/learn/conditional-rendering.md index ecae73e38..c9a8c7314 100644 --- a/src/content/learn/conditional-rendering.md +++ b/src/content/learn/conditional-rendering.md @@ -260,7 +260,7 @@ export default function PackingList() { ### Логический оператор И(`&&`) {/*logical-and-operator-*/} -Еще одно часто встречающееся сокращение [JavaScript логический И (`&&`) оператор.](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Operators/Logical_AND) Внутри React компонентов, часто случается так, что тебе нужно зарендерить JSX, когда условие true, **или не рендерить ничего.** С `&&`, вы можете исходя из условия зарендерить галочку, if `isPacked` это `true`: +Еще одно часто встречающееся сокращение [JavaScript логический оператор И (`&&`).](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Operators/Logical_AND) Внутри React-компонентов он часто используется, когда вам нужно отрендерить JSX, когда условие true, **или не рендерить ничего.** С помощью `&&` вы можете условно рендерить галочку, если `isPacked` равно `true`: ```js return ( From f17b43477492006d92618117c8e37f091fca592c Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Tue, 23 May 2023 00:00:43 +0300 Subject: [PATCH 187/233] Update src/content/learn/conditional-rendering.md Co-authored-by: Nick Tishkevich --- src/content/learn/conditional-rendering.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/conditional-rendering.md b/src/content/learn/conditional-rendering.md index c9a8c7314..34ab01058 100644 --- a/src/content/learn/conditional-rendering.md +++ b/src/content/learn/conditional-rendering.md @@ -212,7 +212,7 @@ return ( -Теперь предположим, что вы хотите обернуть текст завершенного элемента в другой HTML тег, например ``, чтобы вычеркнуть его. Вы можете добавить еще больше новых линий и круглых скобок, чтобы было проще вложить больше JSX в каждом из случаев: +Теперь предположим, что вы хотите обернуть текст завершённого элемента в другой HTML-тег, например ``, чтобы вычеркнуть его. Вы можете добавить ещё больше переносов строк и круглых скобок, чтобы было проще вкладывать JSX в каждом из случаев: From a575a4f6df95ce20348a76c6dba078dbca295c6b Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Tue, 23 May 2023 00:02:06 +0300 Subject: [PATCH 188/233] Update conditional-rendering.md --- src/content/learn/conditional-rendering.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/content/learn/conditional-rendering.md b/src/content/learn/conditional-rendering.md index 34ab01058..ed1ba0902 100644 --- a/src/content/learn/conditional-rendering.md +++ b/src/content/learn/conditional-rendering.md @@ -399,13 +399,13 @@ export default function PackingList() { function Item({ name, isPacked }) { let itemContent = name; if (isPacked) { - itemContent = ( + itemContent = ( {name + " ✔"} ); } - return ( + return (
      5. {itemContent}
      6. From 6aff9705d737b0bc3fa1fbdaac3ccf7d04c37c90 Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Tue, 23 May 2023 00:03:32 +0300 Subject: [PATCH 189/233] Update conditional-rendering.md --- src/content/learn/conditional-rendering.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/conditional-rendering.md b/src/content/learn/conditional-rendering.md index ed1ba0902..5d125dbeb 100644 --- a/src/content/learn/conditional-rendering.md +++ b/src/content/learn/conditional-rendering.md @@ -723,7 +723,7 @@ const drinks = { tea: { part: 'leaf', caffeine: '15–70 мг/чашка', - age: "4,000+ лет", + age: '4,000+ лет', }, coffee: { part: 'bean', From 83dc552df373a047433c0f4a0555ff3a8fe7ace1 Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Tue, 23 May 2023 00:04:35 +0300 Subject: [PATCH 190/233] Update src/content/learn/conditional-rendering.md Co-authored-by: Nick Tishkevich --- src/content/learn/conditional-rendering.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/conditional-rendering.md b/src/content/learn/conditional-rendering.md index 5d125dbeb..7c41865de 100644 --- a/src/content/learn/conditional-rendering.md +++ b/src/content/learn/conditional-rendering.md @@ -536,7 +536,7 @@ export default function PackingList() { #### Показать важность вещи с помощью `&&` {/*show-the-item-importance-with-*/} -В этом примере каждый `Item` получает числовой `importance` проп. Используй `&&` чтобы зарендерить "_(Важность: X)_" в italics стиле, но только для вещей важность которых больше 0. Ваш конечный резульат должен выглядеть вот так вот: +В этом примере каждый `Item` получает числовой проп `importance`. Используйте `&&`, чтобы рендерить "_(Важность: X)_" курсивом только для вещей с ненулевой важностью. Ваш список вещей должен выглядеть следующем образом: - Космический скафандр _(Важность: 9)_ - Шлем с золотым листом From fdd81c3aa8da450c840cbbc6f0bf74b3fbf2cdd1 Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Tue, 23 May 2023 00:06:12 +0300 Subject: [PATCH 191/233] Update src/content/learn/conditional-rendering.md --- src/content/learn/conditional-rendering.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/conditional-rendering.md b/src/content/learn/conditional-rendering.md index 7c41865de..a1176ac14 100644 --- a/src/content/learn/conditional-rendering.md +++ b/src/content/learn/conditional-rendering.md @@ -16,7 +16,7 @@ title: Условный рендеринг -## Условно возвращаемый JSX {/*conditionally-returning-jsx*/} +## Условный возврат JSX {/*conditionally-returning-jsx*/} Допустим, у вас есть компонент `PackingList`, который рендерит несколько компонентов `Item`, который могут быть отмечены как упакованные или нет: From 891a4467af9409526bc56e16d443d1483d01a45a Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Tue, 23 May 2023 00:48:00 +0300 Subject: [PATCH 192/233] Update src/content/learn/render-and-commit.md --- src/content/learn/render-and-commit.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/render-and-commit.md b/src/content/learn/render-and-commit.md index a6261aa0e..661cf0b98 100644 --- a/src/content/learn/render-and-commit.md +++ b/src/content/learn/render-and-commit.md @@ -80,7 +80,7 @@ export default function Image() { После запуска рендера React вызывает ваши компоненты, чтобы определить, что отобразить на экране. **«Рендеринг» — это обращение React к вашим компонентам*. * **На начальном рендере,** React вызовет корневой компонент. -* **Для последующих рендерингов** React будет вызывать функцию компонента, обновление стейта которого вызвало рендеринг. +* **Для последующих ре-рендеров** React вызовет функцию компонента, где обновился стейт и выполнит его ре-рендер. Этот процесс рекурсивен: если обновленный компонент возвращает какой-то другой компонент, React будет рендерить _этот_ компонент следующим, и если этот компонент тоже что-то возвращает, он будет рендерить _этот_ компонент следующим, и так далее. Этот процесс будет продолжаться до тех пор, пока не останется вложенных компонентов и React не будет точно знать, что должно быть отображено на экране. From 50a1849b0c25422179e5abeaaed46ff22983451a Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Tue, 23 May 2023 00:48:11 +0300 Subject: [PATCH 193/233] Update src/content/learn/render-and-commit.md --- src/content/learn/render-and-commit.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/render-and-commit.md b/src/content/learn/render-and-commit.md index 661cf0b98..0eab2c8c1 100644 --- a/src/content/learn/render-and-commit.md +++ b/src/content/learn/render-and-commit.md @@ -146,7 +146,7 @@ img { margin: 0 10px 10px 0; }
        -## Step 3: React фиксирует изменения в DOM {/*step-3-react-commits-changes-to-the-dom*/} +## Часть 3: React фиксирует изменения в DOM {/*step-3-react-commits-changes-to-the-dom*/} После рендеринга (вызова) ваших компонентов React модифицирует DOM. From 13ff5d8623e0f2a7b665d209fb4b54cb25f2aae3 Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Tue, 23 May 2023 00:48:21 +0300 Subject: [PATCH 194/233] Update src/content/learn/render-and-commit.md --- src/content/learn/render-and-commit.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/render-and-commit.md b/src/content/learn/render-and-commit.md index 0eab2c8c1..6efab0cd4 100644 --- a/src/content/learn/render-and-commit.md +++ b/src/content/learn/render-and-commit.md @@ -194,7 +194,7 @@ export default function App() { Это работает, потому что в предыдущий раз React обновил значение `

        ` с новым `time`. Он видит, что `` появляется в том же месте JSX, поэтому React не трогает ``— или его `value`! -## Epilogue: Browser paint {/*epilogue-browser-paint*/} +## Заключительная часть: Браузерная отрисовка {/*epilogue-browser-paint*/} После того как рендеринг завершен и React обновил DOM, браузер перерисовывает экран. Хотя этот процесс известен как «браузерный рендеринг», мы будем называть его «рисованием», чтобы избежать путаницы в документации. From cf0261927eaa4d712a19f7a64a7b0d62459c5859 Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Tue, 23 May 2023 00:48:30 +0300 Subject: [PATCH 195/233] Update src/content/learn/render-and-commit.md --- src/content/learn/render-and-commit.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/render-and-commit.md b/src/content/learn/render-and-commit.md index 6efab0cd4..99734da36 100644 --- a/src/content/learn/render-and-commit.md +++ b/src/content/learn/render-and-commit.md @@ -75,7 +75,7 @@ export default function Image() { -## Step 2: React рендерит ваш компонент {/*step-2-react-renders-your-components*/} +## Часть 2: React рендерит ваш компонент {/*step-2-react-renders-your-components*/} После запуска рендера React вызывает ваши компоненты, чтобы определить, что отобразить на экране. **«Рендеринг» — это обращение React к вашим компонентам*. From e0440eb08438500b87cffc56b8e93f90f6037fec Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Tue, 23 May 2023 00:48:44 +0300 Subject: [PATCH 196/233] Update src/content/learn/render-and-commit.md --- src/content/learn/render-and-commit.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/render-and-commit.md b/src/content/learn/render-and-commit.md index 99734da36..b890af3b3 100644 --- a/src/content/learn/render-and-commit.md +++ b/src/content/learn/render-and-commit.md @@ -29,7 +29,7 @@ title: Рендер и фиксация -## Step 1: Триггер рендера {/*step-1-trigger-a-render*/} +## Часть 1: Триггер рендера {/*step-1-trigger-a-render*/} Рендер компонента происходит по двум причинам: From c492d95aec5e3a92d8702a47b17cbb0f68433505 Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Tue, 23 May 2023 00:49:21 +0300 Subject: [PATCH 197/233] Update src/content/learn/render-and-commit.md Co-authored-by: Fedya Petrakov --- src/content/learn/render-and-commit.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/render-and-commit.md b/src/content/learn/render-and-commit.md index b890af3b3..0c1e39c33 100644 --- a/src/content/learn/render-and-commit.md +++ b/src/content/learn/render-and-commit.md @@ -38,7 +38,7 @@ title: Рендер и фиксация ### Начальный рендер {/*initial-render*/} -Когда ваше приложение запускается, вам необходимо вызвать начальный рендеринг. Фреймворки и песочницы иногда скрывают этот код, но он выполняется вызовом функции [`createRoot`](/reference/react-dom/client/createRoot) с целевым узлом DOM, а затем вызывая его метод `render` вашим компонентом: +Когда ваше приложение запускается, вам необходимо запустить начальный рендеринг. Фреймворки и песочницы иногда скрывают этот код, но это делается вызовом функции [`createRoot`](/reference/react-dom/client/createRoot) с целевым DOM-узлом, а затем вызовом его метода `render` c вашим компонентом: From fcdc18a4684770d6613e81bff8da8f157b807594 Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Tue, 23 May 2023 00:50:28 +0300 Subject: [PATCH 198/233] Update src/content/learn/render-and-commit.md --- src/content/learn/render-and-commit.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/render-and-commit.md b/src/content/learn/render-and-commit.md index 0c1e39c33..667682927 100644 --- a/src/content/learn/render-and-commit.md +++ b/src/content/learn/render-and-commit.md @@ -67,7 +67,7 @@ export default function Image() { ### Ре-рендер, когда стейт обновляется {/*re-renders-when-state-updates*/} -После того как компонент был первоначально отрендерен, вы можете инициировать последующие рендеры, обновляя его состояние с помощью функции [`set`](/reference/react/useState#setstate) Обновление стейта компонента автоматически ставит его в очередь на рендер. (Вы можете представить это как посетителя ресторана, который после первого заказа заказывает чай, десерт и всевозможные вещи, в зависимости от состояния жажды или голода). +После того как компонент был первоначально отрендерен, вы можете инициировать последующие рендеры, обновляя его состояние с помощью функции [`set`](/reference/react/useState#setstate) Обновление состояние компонента автоматически ставит его в очередь на рендер. (Вы можете представить это как посетитель ресторана, который после первого заказа заказывает чай, десерт и всевозможные вещи, в зависимости от состояния жажды или голода). From 432458e3fc80377f36bf70a2ce311b253d11f877 Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Tue, 23 May 2023 00:50:36 +0300 Subject: [PATCH 199/233] Update src/content/learn/render-and-commit.md --- src/content/learn/render-and-commit.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/render-and-commit.md b/src/content/learn/render-and-commit.md index 667682927..76230316e 100644 --- a/src/content/learn/render-and-commit.md +++ b/src/content/learn/render-and-commit.md @@ -34,7 +34,7 @@ title: Рендер и фиксация Рендер компонента происходит по двум причинам: 1. Это его **начальный рендеринг.** -2. Его **стейт** (или стейт его родителя) **был обновлён.** +2. Его **состояние** (или состояние его родителя) **был обновлён.** ### Начальный рендер {/*initial-render*/} From e7da57f3cfa77e97c3c0d594ef0d8dd38acebfe6 Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Tue, 23 May 2023 00:50:49 +0300 Subject: [PATCH 200/233] Update src/content/learn/render-and-commit.md --- src/content/learn/render-and-commit.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/render-and-commit.md b/src/content/learn/render-and-commit.md index 76230316e..d99b3d61b 100644 --- a/src/content/learn/render-and-commit.md +++ b/src/content/learn/render-and-commit.md @@ -65,7 +65,7 @@ export default function Image() { Попробуйте закомментировать вызов `root.render()` и увидите, как компонент исчезнет! -### Ре-рендер, когда стейт обновляется {/*re-renders-when-state-updates*/} +### Ре-рендер, когда состояние обновляется {/*re-renders-when-state-updates*/} После того как компонент был первоначально отрендерен, вы можете инициировать последующие рендеры, обновляя его состояние с помощью функции [`set`](/reference/react/useState#setstate) Обновление состояние компонента автоматически ставит его в очередь на рендер. (Вы можете представить это как посетитель ресторана, который после первого заказа заказывает чай, десерт и всевозможные вещи, в зависимости от состояния жажды или голода). From 965a271720dc97da39d479809bff3cfee3cae728 Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Tue, 23 May 2023 10:21:20 +0300 Subject: [PATCH 201/233] Update src/content/learn/render-and-commit.md --- src/content/learn/render-and-commit.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/render-and-commit.md b/src/content/learn/render-and-commit.md index d99b3d61b..0c55a5580 100644 --- a/src/content/learn/render-and-commit.md +++ b/src/content/learn/render-and-commit.md @@ -206,7 +206,7 @@ export default function App() { 1. Триггер 2. Рендеринг 3. Фиксация -* Вы можете использовать режим Strict Mode для поиска ошибок в ваших компонентах. +* Вы можете использовать режим Строгий режим для поиска ошибок в ваших компонентах. * React не трогает DOM, если результат рендеринга такой же, как и в прошлый раз. From 4ea73aff4cc2f4b008f0b28e255dfb4acbb40948 Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Tue, 23 May 2023 11:05:48 +0300 Subject: [PATCH 202/233] Update src/content/learn/render-and-commit.md Co-authored-by: Nick Tishkevich --- src/content/learn/render-and-commit.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/render-and-commit.md b/src/content/learn/render-and-commit.md index 0c55a5580..cb5ae5c75 100644 --- a/src/content/learn/render-and-commit.md +++ b/src/content/learn/render-and-commit.md @@ -206,7 +206,7 @@ export default function App() { 1. Триггер 2. Рендеринг 3. Фиксация -* Вы можете использовать режим Строгий режим для поиска ошибок в ваших компонентах. +* Вы можете использовать строгий режим для поиска ошибок в ваших компонентах. * React не трогает DOM, если результат рендеринга такой же, как и в прошлый раз. From 414416ecb1bbf977ad39227d52734e7a643fb344 Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Tue, 23 May 2023 11:43:37 +0300 Subject: [PATCH 203/233] Update src/content/learn/conditional-rendering.md Co-authored-by: Nick Tishkevich --- src/content/learn/conditional-rendering.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/conditional-rendering.md b/src/content/learn/conditional-rendering.md index a1176ac14..5f3c0f254 100644 --- a/src/content/learn/conditional-rendering.md +++ b/src/content/learn/conditional-rendering.md @@ -52,7 +52,7 @@ export default function PackingList() { -Обратите внимание, что у некоторых компонентов `Item` установлено свойство `isPacked` в значение `true`, вместо значения `false`. Если `isPacked={true}`, вы хотите добавить галочку(✔) к упакованным вещам. +Обратите внимание, что у некоторых компонентов `Item` проп `isPacked` имеет значение `true`, вместо значения `false`. Если `isPacked={true}`, вы хотите добавить галочку(✔) к упакованным вещам. Можно реализовать это с помощью [управляющей конструкции `if`/`else`](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Statements/if...) таким образом: From b5a8bb3aef116e9feccdcfa67b9b4720993f34d5 Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Tue, 23 May 2023 11:43:45 +0300 Subject: [PATCH 204/233] Update src/content/learn/conditional-rendering.md Co-authored-by: Nick Tishkevich --- src/content/learn/conditional-rendering.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/conditional-rendering.md b/src/content/learn/conditional-rendering.md index 5f3c0f254..a055ffd84 100644 --- a/src/content/learn/conditional-rendering.md +++ b/src/content/learn/conditional-rendering.md @@ -202,7 +202,7 @@ return ( ); ``` -Вы можете читать это как *"if `isPacked` равно true, тогда (`?`) рендерим `name + ' ✔'`, в противном случае (`:`) рендерим `name`"*. +Вы можете читать это как *"если `isPacked` равно true, тогда (`?`) рендерим `name + ' ✔'`, в противном случае (`:`) рендерим `name`"*. From 7e276b440569654883d8ec80e8d667b232fea4ba Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Tue, 23 May 2023 11:43:59 +0300 Subject: [PATCH 205/233] Update src/content/learn/conditional-rendering.md Co-authored-by: Nick Tishkevich --- src/content/learn/conditional-rendering.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/conditional-rendering.md b/src/content/learn/conditional-rendering.md index a055ffd84..7042ef3fc 100644 --- a/src/content/learn/conditional-rendering.md +++ b/src/content/learn/conditional-rendering.md @@ -341,7 +341,7 @@ if (isPacked) { } ``` -[Фигурные скобки открывают "окно в мир JavaScript".](/learn/javascript-in-jsx-with-curly-braces#using-curly-braces-a-window-into-the-javascript-world) Вставьте переменную с фигурными скобками в возвращаемое дерево JSX, вложив ранее вычисленное выражение внутрь JSX: +[Фигурные скобки открывают "окно в мир JavaScript".](/learn/javascript-in-jsx-with-curly-braces#using-curly-braces-a-window-into-the-javascript-world) Вставьте переменную с помощью фигурных скобок в возвращаемое дерево JSX, вложив ранее вычисленное выражение внутрь JSX: ```js
      7. From 86b645f5d899579ebb1b978e483da84ce08e1671 Mon Sep 17 00:00:00 2001 From: qq <79323963+rainyEra@users.noreply.github.com> Date: Tue, 23 May 2023 11:44:10 +0300 Subject: [PATCH 206/233] Update src/content/learn/conditional-rendering.md Co-authored-by: Nick Tishkevich --- src/content/learn/conditional-rendering.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/conditional-rendering.md b/src/content/learn/conditional-rendering.md index 7042ef3fc..8a5368809 100644 --- a/src/content/learn/conditional-rendering.md +++ b/src/content/learn/conditional-rendering.md @@ -208,7 +208,7 @@ return ( #### Эти два примера полностью эквивалентны? {/*are-these-two-examples-fully-equivalent*/} -Если вы знакомы с объектно-ориентированным программированием, вы можете предположить, что два приведенных выше примера немного отличаются друг от друга, поскольку один из них может создавать два разных "экземпляра" `
      8. `. Но JSX-элементы не являются "экземплярами", потому что они не хранят никакого внутреннего состояния и не являются реальными DOM-узлами . Это лёгкие описания, как чертежи. На самом деле эти два примера *совершенно эквивалентны*. В [Сохранение и сброс состояния](/learn/preserving-and-resetting-state) подробно рассказывается о том, как это работает. +Если вы знакомы с объектно-ориентированным программированием, вы можете предположить, что два приведенных выше примера немного отличаются друг от друга, поскольку один из них может создавать два разных "экземпляра" `
      9. `. Но JSX-элементы не являются "экземплярами", потому что они не хранят никакого внутреннего состояния и не являются реальными DOM-узлами. Это лёгкие описания, как чертежи. На самом деле эти два примера *совершенно эквивалентны*. В [Сохранение и сброс состояния](/learn/preserving-and-resetting-state) подробно рассказывается о том, как это работает. From 398ace5b5e36535be19e89edd8c4a20db8a3e042 Mon Sep 17 00:00:00 2001 From: Viacheslav Makarov <9768704+mekarthedev@users.noreply.github.com> Date: Tue, 23 May 2023 16:01:09 +0200 Subject: [PATCH 207/233] Add missing 'it' (#6061) --- src/content/reference/react/useEffect.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/reference/react/useEffect.md b/src/content/reference/react/useEffect.md index dd84fd2ea..8d04f205c 100644 --- a/src/content/reference/react/useEffect.md +++ b/src/content/reference/react/useEffect.md @@ -1089,7 +1089,7 @@ function ChatRoom({ roomId }) { } ``` -**To remove a dependency, you need to ["prove" to the linter *doesn't need* to be a dependency.](/learn/removing-effect-dependencies#removing-unnecessary-dependencies)** For example, you can move `serverUrl` out of your component to prove that it's not reactive and won't change on re-renders: +**To remove a dependency, you need to ["prove" to the linter that it *doesn't need* to be a dependency.](/learn/removing-effect-dependencies#removing-unnecessary-dependencies)** For example, you can move `serverUrl` out of your component to prove that it's not reactive and won't change on re-renders: ```js {1,8} const serverUrl = 'https://localhost:1234'; // Not a reactive value anymore From 09185bcea9c7880763a458e9a68e67e454109791 Mon Sep 17 00:00:00 2001 From: Soichiro Miki Date: Tue, 23 May 2023 23:16:39 +0900 Subject: [PATCH 208/233] Fix a wrong explanation in "Manipulating the DOM with Refs" (#6055) * Fix manipulating-the-dom-with-refs * Update manipulating-the-dom-with-refs.md --------- Co-authored-by: dan --- src/content/learn/manipulating-the-dom-with-refs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/manipulating-the-dom-with-refs.md b/src/content/learn/manipulating-the-dom-with-refs.md index b5c193763..3e91a7694 100644 --- a/src/content/learn/manipulating-the-dom-with-refs.md +++ b/src/content/learn/manipulating-the-dom-with-refs.md @@ -31,7 +31,7 @@ Then, use it to declare a ref inside your component: const myRef = useRef(null); ``` -Finally, pass it to the DOM node as the `ref` attribute: +Finally, pass your ref as the `ref` attribute to the JSX tag for which you want to get the DOM node: ```js
        From 9602971b5d7e085cc3dd084f4ed865a32e14e08e Mon Sep 17 00:00:00 2001 From: Jana Korichneva Date: Tue, 23 May 2023 21:37:00 +0400 Subject: [PATCH 209/233] fix code review comments --- src/content/reference/react/StrictMode.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/content/reference/react/StrictMode.md b/src/content/reference/react/StrictMode.md index f62f3735d..c7efac968 100644 --- a/src/content/reference/react/StrictMode.md +++ b/src/content/reference/react/StrictMode.md @@ -24,7 +24,7 @@ title: ### `` {/*strictmode*/} -Используйте `StrictMode`, для активации дополнительных проверок и предупреждений для вложенного дерева компонентов: +Используйте `StrictMode` для активации дополнительных проверок и предупреждений для вложенного дерева компонентов: ```js import { StrictMode } from 'react'; @@ -38,9 +38,9 @@ root.render( ); ``` -[Больше примеров использования.](#usage) +[Больше примеров использования ниже.](#usage) -Строгий режим активирует следующие поведения в режиме разработки: +Строгий режим активирует следующие варианты поведения в режиме разработки: - Ваши компоненты будут [рендерится повторно](#fixing-bugs-found-by-double-rendering-in-development), чтобы можно было найти баги, вызванные нечистым рендерингом. - Ваши компоненты будут [повторно запускать эффекты](#fixing-bugs-found-by-re-running-effects-in-development), чтобы можно было найти баги, возникающие из-за отсутствия сброса эффекта. @@ -656,7 +656,7 @@ button { margin-left: 10px; } }, [roomId]); ``` -Теперь, когда ваш эффект "сбрасывается" и удаляет устаревшие подключения, утечка устранена. Обратите внимание, что проблема не стала заметной, пока вы не добавили больше функциональности (выпадающий список). +Теперь, когда ваш эффект "убирает" за собой устаревшие подключения, утечка устранена. Обратите внимание, что проблема не стала заметной, пока вы не добавили больше функциональности (выпадающий список). **В исходном примере баг не был очевидным. Теперь давайте обернём исходный код (с багом) в ``:** From 3364c93feb358a7d1ac2e8d8b0468c3e32214062 Mon Sep 17 00:00:00 2001 From: Tunzeki Date: Wed, 24 May 2023 00:04:02 +0100 Subject: [PATCH 210/233] Fix typo: change "intermedinate" to "indeterminate" (#6062) --- src/content/reference/react-dom/components/progress.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/reference/react-dom/components/progress.md b/src/content/reference/react-dom/components/progress.md index fd6c96a1e..b783a102d 100644 --- a/src/content/reference/react-dom/components/progress.md +++ b/src/content/reference/react-dom/components/progress.md @@ -35,7 +35,7 @@ To display a progress indicator, render the [built-in browser ``](http Additionally, `` supports these props: * [`max`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/progress#attr-max): A number. Specifies the maximum `value`. Defaults to `1`. -* [`value`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/progress#attr-value): A number between `0` and `max`, or `null` for intermedinate progress. Specifies how much was done. +* [`value`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/progress#attr-value): A number between `0` and `max`, or `null` for indeterminate progress. Specifies how much was done. --- From 6b60ef4e354fb7de8c1d94541e3f1ea1fb040059 Mon Sep 17 00:00:00 2001 From: maryna <59647513+maridoroshuk@users.noreply.github.com> Date: Sat, 27 May 2023 08:26:44 +0200 Subject: [PATCH 211/233] fix typos --- .../learn/referencing-values-with-refs.md | 64 +++++++++---------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/src/content/learn/referencing-values-with-refs.md b/src/content/learn/referencing-values-with-refs.md index 6bb73f7fd..77f337d88 100644 --- a/src/content/learn/referencing-values-with-refs.md +++ b/src/content/learn/referencing-values-with-refs.md @@ -1,17 +1,17 @@ --- -title: 'Referencing Values with Refs' +title: 'Обращаемся к значением через рефы' --- -Для того, чтобы компонент "запомнил" какие-либо данные, но изменения этих данных не [вызывали новый рендер](/learn/render-and-commit), вы можете использовать *реф*. +Для того, чтобы компонент «запомнил» какие-либо данные, но изменения этих данных не [вызывали новый рендер](/learn/render-and-commit), вы можете использовать *реф*. -- Как добавлять реф в ваш компонент -- Как обновлять значение рефа +- Как добавить реф в ваш компонент +- Как обновить значение рефа - Отличие рефа от состояния - Как безопасно использовать рефы @@ -19,7 +19,7 @@ title: 'Referencing Values with Refs' ## Добавляем реф в ваш компонент {/*adding-a-ref-to-your-component*/} -Чтобы добавить реф в ваш компонент импортируйте хук `useRef` из React: +Чтобы добавить реф в ваш компонент, импортируйте хук `useRef` из React: ```js import { useRef } from 'react'; @@ -32,6 +32,7 @@ const ref = useRef(0); ``` `useRef` возвращает следующий объект: + ```js { current: 0 // Значение, которое вы передали в useRef @@ -40,7 +41,7 @@ const ref = useRef(0); -Получить доступ к значению рефа можно через свойство `ref.current`. Это значение намеренно является мутируемым, т.е. оно доступно как для чтения, так и для изменения. По сути, это как секретный карман, за которым React не следит. (Благодаря этому, реф является "лазейкой" в однонаправленном потоке данных React. Подробнее об этом ниже!) +Получить доступ к значению рефа можно через свойство `ref.current`. Это значение намеренно является мутируемым, т.е. оно доступно как для чтения, так и для изменения. По сути, это как секретный карман, за которым React не следит. (Благодаря этому, реф является «лазейкой» в однонаправленном потоке данных React. Подробнее об этом ниже!) В примере ниже создадим кнопку, которая будет увеличивать `ref.current` на каждый клик: @@ -67,20 +68,20 @@ export default function Counter() { -Здесь реф ссылается на число, как и в случае с [состоянием](/learn/state-a-components-memory), вы можете ссылаться на что угодно: на строку, объект, или даже на функцию. В отличии от состояния, реф это обычный JavaScript объект со свойством `current`, которое можно читать и изменять. +Здесь реф ссылается на число, но как и в случае с [состоянием](/learn/state-a-components-memory), вы можете ссылаться на что угодно: на строку, объект или даже на функцию. В отличии от состояния, реф—это обычный JavaScript-объект со свойством `current`, которое можно читать и изменять. Имейте в виду, что **изменение реф не вызовет повторный рендер на каждое изменение.** Рефы будут сохраняться между повторными рендерами, как и состояние. Однако, обновление состояние вызывает новый рендер. А изменение рефа нет! ## Пример: создадим секундомер {/*example-building-a-stopwatch*/} -Рефы и состояние можно использовать в одном компоненте. Например, создадим секундомер, который можно будет запускать и останавливать нажатием кнопки. Чтобы отобразить сколько времени прошло с момента клика "Start", нужно следить за моментом клика и за текущим временем. **Так как эти данные используются при рендере, их лучше хранить в состоянии:** +Рефы и состояние можно использовать в одном компоненте. Например, создадим секундомер, который можно будет запускать и останавливать нажатием кнопки. Чтобы отобразить сколько времени прошло с момента клика «Start», нужно следить за моментом клика и за текущим временем. **Так как эти данные используются при рендере, их лучше хранить в состоянии:** ```js const [startTime, setStartTime] = useState(null); const [now, setNow] = useState(null); ``` -Чтобы обновлять время каждые 10 миллисекунд, после того как пользователь нажимает "Start", будем использовать [`setInterval`](https://developer.mozilla.org/docs/Web/API/setInterval): +Чтобы обновлять время каждые 10 миллисекунд, после того как пользователь нажимает «Start», будем использовать [`setInterval`](https://developer.mozilla.org/docs/Web/API/setInterval): @@ -120,7 +121,7 @@ export default function Stopwatch() { -Когда нажата кнопка "Stop", нужно очистить текущий интервал, чтобы значение состояния `now` перестало обновляться. Для реализации можно использовать вызов[`clearInterval`](https://developer.mozilla.org/en-US/docs/Web/API/clearInterval), но интервалу нужно задать ID, которое возвращается при вызове `setInterval`, когда пользователь нажал "Start". ID интервала нужно где-то сохранить. **Мы можем сохранить его в реф, т.к. он никак не влияет на рендер:** +Когда нажата кнопка «Stop», нужно очистить текущий интервал, чтобы значение состояния `now` перестало обновляться. Для реализации можно использовать вызов[`clearInterval`](https://developer.mozilla.org/en-US/docs/Web/API/clearInterval), но интервалу нужно задать ID, которое возвращается при вызове `setInterval`, когда пользователь нажал «Start». ID интервала нужно где-то сохранить. **Поскольку ID интервала не используется для рендера, вы можете сохранить его в реф:** @@ -167,17 +168,17 @@ export default function Stopwatch() { -Когда какие-то данные используются для рендера, используйте состояние. Когда данные нужны только для обработчиков событий и изменение этих дынных не требуют повторного рендера, использование реф будет более эффективным. +Когда какие-то данные используются для рендера, держите её в состоянии. Когда данные нужны только для обработчиков событий, и изменение этих данных не требуют повторного рендера, использование реф будет более эффективным. ## Отличие рефа от состояния {/*differences-between-refs-and-state*/} -Может показаться, что рефы менее "строгие" чем состояние—их можно изменять напрямую, вместо использования функции для обновления состояния. Но в большинстве случаев, вам захочется использовать состояние. Рефы—это "лазейка", которую не рекомендуется использовать слишком часто. Ниже сравнение рефа и состояния: +Может показаться, что рефы менее «строгие», чем состояние—их можно изменять напрямую, вместо использования функции для обновления состояния. Но в большинстве случаев вам захочется использовать состояние. Рефы—это «лазейка», которую не рекомендуется использовать слишком часто. Ниже сравнение рефа и состояния: | refs | state | | ------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | | `useRef(initialValue)` возвращает `{ current: initialValue }` | `useState(initialValue)` возвращает текущее значение состояния и функцию-сеттер для его обновления ( `[value, setValue]`) | | При изменении не вызывает повторный рендер. | При изменении вызывает повторный рендер. | -| Мутабельный—можно изменять и обновлять значение `current` независимо от процесса рендера. | "Иммутабельный"—обязательно использовать функцию -сеттер, чтобы добавить изменение состояния в очередь обновлений. | +| Мутабельный—можно изменять и обновлять значение `current` независимо от процесса рендера. | «Иммутабельный»—обязательно использовать функцию-сеттер, чтобы добавить изменение состояния в очередь обновлений. | | Не рекомендуется читать (или изменять) значение `current` во время рендера. | Можно читать значение состояния в любое время. Однако, за каждым рендером закреплён свой [снимок](/learn/state-as-a-snapshot) состояния, который не будет изменяться. В следующем примере создадим кнопку счётчика, которая использует состояние: @@ -231,13 +232,13 @@ export default function Counter() { -Именно поэтому, чтение из `ref.current` во время рендера приводит к непредсказуемому результату. Используйте состояние, если во время рендера вам точно нужно читать данные из него! +Именно поэтому чтение из `ref.current` во время рендера приводит к непредсказуемому результату. Используйте состояние, если во время рендера вам точно нужно читать данные из него! #### Как работает useRef изнутри? {/*how-does-use-ref-work-inside*/} -Хотя оба хука `useState` и `useRef` могут быть импортированы из React, `useRef` может быть реализован поверх `useState`. Можно представлять, что внутри React, `useRef` реализован следующим образом: +Хотя оба хука `useState` и `useRef` могут быть импортированы из React, `useRef` может быть реализован поверх `useState`. Можно представлять, что внутри React `useRef` реализован следующим образом: ```js // Внутри React @@ -247,7 +248,7 @@ function useRef(initialValue) { } ``` -Во время первого рендера, `useRef` возвращает `{ current: initialValue }`. Этот объект сохраняется внутри React, поэтому во время следующего рендера вернётся точно такой же объект. Обратите внимание, что функция для обновления состояния в этом примере не используется. В этом нет необходимости, т.к. `useRef` всегда возвращает один и тот же объект! +Во время первого рендера `useRef` возвращает `{ current: initialValue }`. Этот объект сохраняется внутри React, поэтому во время следующего рендера вернётся точно такой же объект. Обратите внимание, что функция для обновления состояния в этом примере не используется. В этом нет необходимости, т.к. `useRef` всегда возвращает один и тот же объект! React предоставляет встроенный хук `useRef`, т.к. это достаточно часто встречается на практике. Но можно представлять себе, что это обычное значение состояния, но без функции обновления. Если вы знакомы с объектно-ориентированным программированием, рефы могут напоминать вам поля экземпляра--но вместо `this.something` используется `somethingRef.current`. @@ -268,8 +269,7 @@ React предоставляет встроенный хук `useRef`, т.к. э Следуйте следующим принципам, чтобы сделать ваши компоненты более предсказуемыми: - **Используйте рефы как лазейку.** Использование рефов является оправданным, когда вы работаете со сторонними системами или с API браузера. Если большая часть логики вашего приложения и потока данных зависит от рефов, скорее всего вам стоит переосмыслить свой подход. -- **Не читайте и не изменяйте `ref.current` во время рендера.** Если необходимо использовать какие-то данные во время рендера, используйте [состояние](/learn/state-a-components-memory) вместо рефа. Даже просто чтение во время рендера делает поведение вашего компонента менее предсказуемым, поскольку React ничего не знает об изменении `ref.current`. (Единственным исключением является `if (!ref.current) ref.current = new Thing()`, где реф устанавливается единожды во время первого рендера.) - +- **Не читайте и не изменяйте `ref.current` во время рендера.** Если необходимо использовать какие-то данные во время рендера, используйте [состояние](/learn/state-a-components-memory) вместо рефа. Даже просто чтение во время рендера делает поведение вашего компонента менее предсказуемым, поскольку React ничего не знает об изменении `ref.current`. (Единственным исключением является `if (!ref.current) ref.current = new Thing()`, где реф устанавливается единожды, во время первого рендера.) Ограничения React при использовании состояния никак не влияют на рефы. Например, состояние ведёт себя как [снимок для каждого рендера](/learn/state-as-a-snapshot) и [не обновляется синхронно.](/learn/queueing-a-series-of-state-updates) Но при изменении текущего значения реф, оно изменяется сразу же: @@ -278,18 +278,18 @@ ref.current = 5; console.log(ref.current); // 5 ``` -Это обусловлено тем, что **реф—это обычный JavaScript объект,** и ведёт себя как объект. +Это обусловлено тем, что **реф—это обычный JavaScript-объект,** и ведёт себя как объект. Когда вы работаете с рефами, вам не нужно беспокоится о том, чтобы [избегать мутаций](/learn/updating-objects-in-state). До тех пор пока объект, который вы мутируете не используется для рендера, React нет дела, что вы делаете с рефами и их значениями. ## Рефы и DOM {/*refs-and-the-dom*/} -Вы можете использовать реф в качестве ссылки на любое значение. Однако, на практике рефы часто используются для доступа к DOM-элементам. Например, когда нужно программно сфокусироваться на элементе `input`. Когда вы устанавливаете `ref` через атрибут, `
        `, React сохранит соответствующий DOM-элемент в качестве значения `myRef.current`. Вы можете больше прочитать об этом в [Manipulating the DOM with Refs.](/learn/manipulating-the-dom-with-refs). +Вы можете использовать реф в качестве ссылки на любое значение. Однако, на практике рефы часто используются для доступа к DOM-элементам. Например, когда нужно программно сфокусироваться на элементе `input`. Когда вы устанавливаете `ref` через атрибут, `
        `, React сохранит соответствующий DOM-элемент в качестве значения `myRef.current`. Вы можете больше прочитать об этом в [Manipulating the DOM with Refs.](/learn/manipulating-the-dom-with-refs). -- Рефы это лазейка для хранения значений, которые не используются при рендере. Чаще всего вы можете обойтись без них. -- Реф—это обычный JavaScript объект с единственным свойством `curent`, которое доступно как для чтения, так и для записи. +- Рефф—это лазейка для хранения значений, которые не используются при рендере. Чаще всего вы можете обойтись без них. +- Реф—это обычный JavaScript-объект с единственным свойством `curent`, которое доступно как для чтения, так и для записи. - Вы можете использовать реф, вызвав хук `useRef` из React. - Рефы позволяют вам сохранить данные между перерисовками компонента, как и в случае с состоянием. - В отличии от состояния, запись нового значения в `ref.current` не спровоцирует повторный рендер компонента. @@ -303,11 +303,11 @@ console.log(ref.current); // 5 #### Исправьте неработающий input в чате {/*fix-a-broken-chat-input*/} -Введите сообщение и нажмите "Send". Можно заметить трёхсекундную задержку перед тем как появится модальное окно с сообщением "Sent!". Во время этой задержки появляется кнопка "Undo". Кликните по ней. Предполагается, что кнопка "Undo" предотвратит появление сообщения "Sent!". Это происходит из-за вызова [`clearTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/clearTimeout) для сохранения ID во время `handleSend`. Однако, даже после клика "Undo", сообщение все ещё появляется. Попробуйте разобраться, почему этот код не работает и исправить его. +Введите сообщение и нажмите «Send». Можно заметить трёхсекундную задержку перед тем, как появится модальное окно с сообщением «Sent!». Во время этой задержки появляется кнопка «Undo». Кликните по ней. Предполагается, что кнопка «Undo» предотвратит появление сообщения «Sent!». Это происходит из-за вызова [`clearTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/clearTimeout) для сохранения ID во время `handleSend`. Однако, даже после клика «Undo», сообщение все ещё появляется. Попробуйте разобраться, почему этот код не работает, и исправить его. -Обычные переменные, такие как `let timeoutID` не "выживают" между повторными рендерами, потому что каждый рендер запускает компонент (и инициализирует переменные) с нуля. +Обычные переменные, такие как `let timeoutID` не «выживают» между повторными рендерами, потому что каждый рендер запускает компонент (и инициализирует переменные) с нуля. @@ -360,7 +360,7 @@ export default function Chat() { -Каждый раз когда компонент рендерится повторно (например, когда устанавливается новое состояние), все локальные переменные инициализируются с нуля. Поэтому вы не можете сохранить ID таймера в обычную переменную такую, как `timeoutID` и ожидать, что обработчик сможет "увидеть" её в будущем. Вместо этого сохраните её в реф, который React сохраняет между рендерами. +Каждый раз когда компонент рендерится повторно (например, когда устанавливается новое состояние), все локальные переменные инициализируются с нуля. Поэтому вы не можете сохранить ID таймера в обычную переменную, как `timeoutID` и ожидать, что обработчик сможет «увидеть» её в будущем. Вместо этого сохраните её в реф, который React сохраняет между рендерами. @@ -414,7 +414,7 @@ export default function Chat() { #### Исправьте ошибку при повторном рендере компонента {/*fix-a-component-failing-to-re-render*/} -Предполагается, что кнопка должна переключаться между отображением "On" и "Off". Но всегда отображается "Off". Что не так с эти кодом? Попробуйте исправить. +Предполагается, что кнопка должна переключаться между отображением «On» и «Off». Но всегда отображается «Off». Что не так с эти кодом? Попробуйте исправить. @@ -438,7 +438,7 @@ export default function Toggle() { -В этом примере текущее значение реф используется для вычисления того, что отобразится на странице: `{isOnRef.current ? 'On' : 'Off'}`. Это признак того, что эти данные не должны хранится в рефе, и вместо этого, должны храниться в состоянии. Чтобы исправить, удалите реф и используйте состояние вместо него: +В этом примере текущее значение реф используется для вычисления того, что отобразится на странице: `{isOnRef.current ? 'On' : 'Off'}`. Это признак того, что эти данные не должны хранится в рефе, и вместо этого должны храниться в состоянии. Чтобы исправить, удалите реф и используйте состояние вместо него: @@ -464,7 +464,7 @@ export default function Toggle() { #### Исправьте debouncing {/*fix-debouncing*/} -В данном примере все обработчики событий для кнопок являются ["debounced".](https://redd.one/blog/debounce-vs-throttle) Чтобы понять, как это работает, кликните на одну из кнопок. Обратите внимание, что сообщение появляется через секунду. Если нажать на кнопку во время ожидания сообщения, таймер сбросится. Таким образом, если вы продолжите кликать одну и ту же кнопку много раз, сообщение не появится до тех пор, пока не пройдёт секунда _после_ последнего клика. Debouncing позволяет вам установить задержку до тех пор, пока пользователь "не прекратит делать что-то", прежде чем произойдёт какое-то действие. +В данном примере все обработчики событий для кнопок являются ["debounced".](https://redd.one/blog/debounce-vs-throttle) Чтобы понять, как это работает, кликните на одну из кнопок. Обратите внимание, что сообщение появляется через секунду. Если нажать на кнопку во время ожидания сообщения, таймер сбросится. Таким образом, если вы продолжите кликать одну и ту же кнопку много раз, сообщение не появится до тех пор, пока не пройдёт секунда _после_ последнего клика. Debouncing позволяет вам установить задержку до тех пор, пока пользователь «не прекратит делать что-то», прежде чем произойдёт какое-то действие. Этот пример работает, но не совсем как было задумано. Кнопки не являются независимыми. Чтобы увидеть проблему, кликните на одну из кнопок и затем кликните на другую кнопку. Мы ожидаем увидеть два сообщения, которые привязаны к каждой кнопке. Но мы увидим только сообщение последней. Сообщение первой кнопки потерялось. @@ -525,7 +525,7 @@ button { display: block; margin: 10px; } -Переменная `timeoutID` была использована во всех компонентах. Поэтому клик по второй кнопке сбрасывал таймер ожидания первой. Чтобы это исправить, следует хранить таймер в рефе. Каждая кнопка получит свой реф и вместе кнопки будут работать корректно. Обратите внимание, что быстрый клик по двум кнопкам покажет оба сообщения. +Переменная `timeoutID` была использована во всех компонентах. Поэтому клик по второй кнопке сбрасывал таймер ожидания первой. Чтобы это исправить, следует хранить таймер в рефе. Каждая кнопка получит свой реф, и вместе кнопки будут работать корректно. Обратите внимание, что быстрый клик по двум кнопкам покажет оба сообщения. @@ -579,9 +579,9 @@ button { display: block; margin: 10px; } #### Прочитайте самое новое состояние {/*read-the-latest-state*/} -В данном примере, после нажатия "Send" есть небольшая задержка прежде, чем появится сообщение. Введите "hello", нажмите Send, и потом снова отредактируйте поле ввода. Несмотря на редактирование, модальное окно все ещё показывает "hello" (эта строка была значением состояния [во время](/learn/state-as-a-snapshot#state-over-time), когда произошёл клик по кнопке). +В данном примере, после нажатия «Send» есть небольшая задержка прежде чем появится сообщение. Введите «hello», нажмите Send и потом снова отредактируйте поле ввода. Несмотря на редактирование, модальное окно все ещё показывает «hello» (эта строка была значением состояния [во время](/learn/state-as-a-snapshot#state-over-time), когда произошёл клик по кнопке). -Как правило, именно такое поведение вам необходимо в вашем приложении. Тем не менее, могут возникнуть случаи, когда будет необходимость получить доступ к самой _последней_ версии состояния в каком-либо асинхронном коде. Можете ли вы найти решение, чтобы модальное окно показывало _текущий_ текст поля ввода, вместо состояния, которое сохранилось во время клика? +Как правило, именно такое поведение вам необходимо в вашем приложении. Тем не менее, могут возникнуть случаи, когда будет необходимость получить доступ к самой _последней_ версии состояния в каком-либо асинхронном коде. Можете ли вы найти решение, чтобы модальное окно показывало _текущий_ текст поля ввода вместо состояния, которое сохранилось во время клика? @@ -657,4 +657,4 @@ export default function Chat() { - + \ No newline at end of file From ad4f5c7c9555f65d6b889e85427ba3fdfa4e7159 Mon Sep 17 00:00:00 2001 From: Serhii Palamarchuk Date: Tue, 30 May 2023 19:57:57 +0300 Subject: [PATCH 212/233] Update NextJs link (#6053) --- .../reference/react-dom/server/renderToPipeableStream.md | 2 +- .../reference/react-dom/server/renderToReadableStream.md | 2 +- src/content/reference/react/Suspense.md | 2 +- src/content/reference/react/useDeferredValue.md | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/content/reference/react-dom/server/renderToPipeableStream.md b/src/content/reference/react-dom/server/renderToPipeableStream.md index dee690372..6a9021e02 100644 --- a/src/content/reference/react-dom/server/renderToPipeableStream.md +++ b/src/content/reference/react-dom/server/renderToPipeableStream.md @@ -286,7 +286,7 @@ Streaming does not need to wait for React itself to load in the browser, or for **Only Suspense-enabled data sources will activate the Suspense component.** They include: -- Data fetching with Suspense-enabled frameworks like [Relay](https://relay.dev/docs/guided-tour/rendering/loading-states/) and [Next.js](https://nextjs.org/docs/advanced-features/react-18) +- 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) Suspense **does not** detect when data is fetched inside an Effect or event handler. diff --git a/src/content/reference/react-dom/server/renderToReadableStream.md b/src/content/reference/react-dom/server/renderToReadableStream.md index d6d5b3264..8ef42aa71 100644 --- a/src/content/reference/react-dom/server/renderToReadableStream.md +++ b/src/content/reference/react-dom/server/renderToReadableStream.md @@ -285,7 +285,7 @@ Streaming does not need to wait for React itself to load in the browser, or for **Only Suspense-enabled data sources will activate the Suspense component.** They include: -- Data fetching with Suspense-enabled frameworks like [Relay](https://relay.dev/docs/guided-tour/rendering/loading-states/) and [Next.js](https://nextjs.org/docs/advanced-features/react-18) +- 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) Suspense **does not** detect when data is fetched inside an Effect or event handler. diff --git a/src/content/reference/react/Suspense.md b/src/content/reference/react/Suspense.md index f24c98c7d..27add6035 100644 --- a/src/content/reference/react/Suspense.md +++ b/src/content/reference/react/Suspense.md @@ -252,7 +252,7 @@ async function getAlbums() { **Only Suspense-enabled data sources will activate the Suspense component.** They include: -- Data fetching with Suspense-enabled frameworks like [Relay](https://relay.dev/docs/guided-tour/rendering/loading-states/) and [Next.js](https://nextjs.org/docs/advanced-features/react-18) +- 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) Suspense **does not** detect when data is fetched inside an Effect or event handler. diff --git a/src/content/reference/react/useDeferredValue.md b/src/content/reference/react/useDeferredValue.md index 3f2a8a5d9..f25054542 100644 --- a/src/content/reference/react/useDeferredValue.md +++ b/src/content/reference/react/useDeferredValue.md @@ -84,7 +84,7 @@ During updates, the deferred value will "lag behin This example assumes you use one of Suspense-enabled data sources: -- Data fetching with Suspense-enabled frameworks like [Relay](https://relay.dev/docs/guided-tour/rendering/loading-states/) and [Next.js](https://nextjs.org/docs/advanced-features/react-18) +- 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) [Learn more about Suspense and its limitations.](/reference/react/Suspense) From 4184c0f5608ef80d6cec4e1c42dfa9c6f3c9ad92 Mon Sep 17 00:00:00 2001 From: J <124119483+escwxyz@users.noreply.github.com> Date: Wed, 31 May 2023 16:15:21 +0200 Subject: [PATCH 213/233] Fix a missing word in useLayoutEffect (#6078) --- src/content/reference/react/useLayoutEffect.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/reference/react/useLayoutEffect.md b/src/content/reference/react/useLayoutEffect.md index d30ebbd16..5af3ec5a6 100644 --- a/src/content/reference/react/useLayoutEffect.md +++ b/src/content/reference/react/useLayoutEffect.md @@ -26,7 +26,7 @@ useLayoutEffect(setup, dependencies?) ### `useLayoutEffect(setup, dependencies?)` {/*useinsertioneffect*/} -Call `useLayoutEffect` perform the layout measurements before the browser repaints the screen: +Call `useLayoutEffect` to perform the layout measurements before the browser repaints the screen: ```js import { useState, useRef, useLayoutEffect } from 'react'; From ca93140eb98a7ff4364a719075fccea980c55b55 Mon Sep 17 00:00:00 2001 From: Ahmed Abdelbaset Date: Fri, 2 Jun 2023 14:42:16 +0300 Subject: [PATCH 214/233] Fix option's mdn link (#6080) --- src/content/reference/react-dom/components/option.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/reference/react-dom/components/option.md b/src/content/reference/react-dom/components/option.md index 8d930523f..84725854c 100644 --- a/src/content/reference/react-dom/components/option.md +++ b/src/content/reference/react-dom/components/option.md @@ -23,7 +23,7 @@ The [built-in browser `