From ab98dee80eb8e970a966dcac083c85db8f5f835b Mon Sep 17 00:00:00 2001 From: Yevhen Stuzhuk Date: Sat, 14 Sep 2024 06:58:11 +0300 Subject: [PATCH] Apply suggestions from code review Co-authored-by: Alina Listunova --- src/content/reference/react/useContext.md | 81 ++++++++++++----------- 1 file changed, 41 insertions(+), 40 deletions(-) diff --git a/src/content/reference/react/useContext.md b/src/content/reference/react/useContext.md index db5f84183..947d82cdc 100644 --- a/src/content/reference/react/useContext.md +++ b/src/content/reference/react/useContext.md @@ -4,7 +4,7 @@ title: useContext -`useContext` це хук, який дозволяє читати [контекст](/learn/passing-data-deeply-with-context) компонента та підписуватись на нього. +`useContext` це хук, який дозволяє читати [контекст](/learn/passing-data-deeply-with-context) компонента та підписуватися на нього. ```js const value = useContext(SomeContext) @@ -50,7 +50,8 @@ function MyComponent() { ## Використання {/*usage*/} -### Передача даних глибоко в дерево компонентів {/*passing-data-deeply-into-the-tree*/} + +### Передавання даних глибоко в дерево компонентів {/*passing-data-deeply-into-the-tree*/} Викликайте `useContext` на верхньому рівні вашого компонента, щоб зчитувати та підписуватися на [контекст.](/learn/passing-data-deeply-with-context) @@ -62,9 +63,9 @@ function Button() { // ... ``` -`useContext` повертає значення для контексту, який ви передали. Щоб визначити це значення, React шукає по дереву компонентів та знаходить **найближчого провайдера вище** для цього конкретного контексту. +`useContext` повертає значення для контексту, який ви передали. Щоб визначити це значення, React шукає деревом компонентів та знаходить **найближчого провайдера вище** для цього конкретного контексту. -Щоб передати контекст до компонента `Button`, оберніть його або одного з його батьківських компонентів у відповідний провайдер: +Щоб передати контекст до компонента `Button`, обгорніть його або один із його батьківських компонентів у відповідний провайдер: ```js [[1, 3, "ThemeContext"], [2, 3, "\\"dark\\""], [1, 5, "ThemeContext"]] function MyPage() { @@ -80,11 +81,11 @@ function Form() { } ``` -Не має значення скільки шарів компонентів між провайдером та `Button`. Якщо `Button` у *будь-якому* місці в середині `Form` викликає `useContext(ThemeContext)`, він отримає `"dark"` у якості значення. +Не має значення, скільки шарів компонентів між провайдером та `Button`. Якщо `Button` у *будь-якому* місці всередині `Form` викликає `useContext(ThemeContext)`, він отримає `"dark"` у якості значення. -`useContext()` завжди шукає найближчого провайдера *над* компонентом, що його викликає. Він просувається вгору по дереву компонентів і **не** враховує провайдери в тому самому компоненті, де викликається `useContext()`. +`useContext()` завжди шукає найближчого провайдера *над* компонентом, що його викликає. Він просувається вгору деревом компонентів і **не** враховує провайдери в тому самому компоненті, де викликається `useContext()`. @@ -299,13 +300,13 @@ function Button({ children }) { -Зверніть увагу, що `value="dark"` передає рядок `"dark"`, але `value={theme}` передає значення змінної JavaScript `theme` з [фігурними дужками JSX.](/learn/javascript-in-jsx-with-curly-braces) Фігурні дужки також дозволяють передавати значення контексту, які не є рядками. +Зверніть увагу, що `value="dark"` передає стрічкову змінну `"dark"`, але `value={theme}` передає значення змінної JavaScript `theme` із [фігурними дужками JSX.](/learn/javascript-in-jsx-with-curly-braces) Фігурні дужки також дають змогу передавати значення контексту, які не є стрічками. #### Оновлення об'єкта через контекст {/*updating-an-object-via-context*/} -У цьому прикладі є змінна стану `currentUser`, яка містить об'єкт. Об'єднайте `{ currentUser, setCurrentUser }` в один об'єкт і передайте його як значення контексту через `value={}`. Це дозволить будь-якому компоненту нижче, наприклад `LoginButton`, зчитувати як значення `currentUser`, так і функцію `setCurrentUser`, і викликати її за потреби. +У цьому прикладі є змінна стану `currentUser`, яка містить об'єкт. Об'єднайте `{ currentUser, setCurrentUser }` в один об'єкт і передайте його як значення контексту через `value={}`. Це дасть змогу будь-якому компоненту нижче, як-от `LoginButton`, зчитувати як значення `currentUser`, так і функцію `setCurrentUser`, а також викликати останню за потреби. @@ -397,7 +398,7 @@ label { #### Декілька контекстів {/*multiple-contexts*/} -У цьому прикладі є два незалежних контексти. `ThemeContext` надає поточну тему, яка є рядком, тоді як `CurrentUserContext` містить об'єкт, що представляє поточного користувача. +У цьому прикладі є два незалежних контексти. `ThemeContext` надає поточну тему як стрічкову змінну, тоді як `CurrentUserContext` містить об'єкт, що представляє поточного користувача. @@ -564,7 +565,7 @@ label { #### Винесення провайдерів в окремий компонент {/*extracting-providers-to-a-component*/} -Коли ваш додаток зростає, ближче до кореня з'являється "піраміда" контекстів . Це цілком нормально. Однак, якщо вам не подобається складна ієрархія з естетичної точки зору, ви можете винести провайдери в окремий компонент. У цьому прикладі `MyProviders` приховує "технічні деталі" і рендерить передані йому дочірні компоненти всередині необхідних провайдерів. Зверніть увагу, що стан `theme` і `setTheme` необхідний безпосередньо в компоненті `MyApp`, тому `MyApp` все ще керує цією частиною стану. +Коли ваш додаток зростає, ближче до кореня з'являється "піраміда" контекстів. Це цілком нормально. Однак, якщо вам не подобається складна ієрархія з естетичної точки зору, ви можете винести провайдери в окремий компонент. У цьому прикладі `MyProviders` приховує "технічні деталі" і рендерить передані йому дочірні компоненти всередині необхідних провайдерів. Зверніть увагу, що стан `theme` і `setTheme` необхідний безпосередньо в компоненті `MyApp`, тому `MyApp` все ще керує цією частиною стану. @@ -737,9 +738,9 @@ label { -#### Масштабування з використанням контексту та ред'юсера {/*scaling-up-with-context-and-a-reducer*/} +#### Масштабування з використанням контексту та редюсера {/*scaling-up-with-context-and-a-reducer*/} -У більших додатках часто поєднують контекст з [ред'юсером](/reference/react/useReducer), щоб винести логіку, пов'язану зі станом, за межі компонентів. У цьому прикладі вся "інфраструктура" прихована в `TasksContext.js`, який містить ред'юсер і два окремих контексти. +У більших застосунках часто поєднують контекст із [редюсером](/reference/react/useReducer), щоб винести пов'язану зі станом логіку за межі компонентів. У цьому прикладі вся "інфраструктура" прихована в `TasksContext.js`, який містить редюсер і два окремих контексти. Перегляньте [повний приклад](/learn/scaling-up-with-reducer-and-context) цього процесу. @@ -821,7 +822,7 @@ function tasksReducer(tasks, action) { const initialTasks = [ { id: 0, text: 'Шлях філософа', done: true }, { id: 1, text: 'Відвідати храм', done: false }, - { id: 2, text: 'Випити матча', done: false } + { id: 2, text: 'Випити матчу', done: false } ]; ``` @@ -835,7 +836,7 @@ export default function AddTask() { return ( <> setText(e.target.value)} /> @@ -947,25 +948,25 @@ ul, li { margin: 0; padding: 0; } --- -### Визначення значення за замовчуванням {/*specifying-a-fallback-default-value*/} +### Задання початкового значення {/*specifying-a-fallback-default-value*/} -Якщо React не знайде жодного провайдера для конкретного контексту у дереві батьківських компонентів, значення, яке повертає `useContext()`, буде дорівнювати вихідному значенню, що ви вказали під час [створення контексту](/reference/react/createContext): +Якщо React не знайде жодного провайдера для конкретного контексту у дереві батьківських компонентів, значення, яке повертає `useContext()`, буде дорівнювати початковому значенню, вказаному під час [створення контексту](/reference/react/createContext): ```js [[1, 1, "ThemeContext"], [3, 1, "null"]] const ThemeContext = createContext(null); ``` -Вихідне значення **ніколи не змінюється**. Якщо ви хочете оновити контекст, використовуйте його разом зі станом, як [описано вище.](#updating-data-passed-via-context) +Початкове значення **ніколи не змінюється**. Якщо ви хочете оновити контекст, використовуйте його разом зі станом, як [описано вище.](#updating-data-passed-via-context) -Зазвичай замість `null` можна визначити якесь більш змістовне вихідне значення, наприклад: +Зазвичай замість `null` можна визначити якесь більш змістовне початкове значення, наприклад: ```js [[1, 1, "ThemeContext"], [3, 1, "light"]] const ThemeContext = createContext('light'); ``` -Отже, якщо випадково відрендерите якийсь компонент без відповідного провайдера, це не призведе до помилки. І також допоможе компонентам добре працювати в тестовому середовищі, не вимагаючи налаштування провайдерів. +Так, якщо випадково відрендерите якийсь компонент без відповідного провайдера, це не призведе до помилки. І також допоможе компонентам відпрацювати в тестовому середовищі без налаштування провайдерів. -У прикладі нижче кнопка "Перемкнути тему" завжди буде світлою, тому що вона **знаходиться поза жодним провайдером теми**, і значенням теми за замовчуванням є `'light'`. Спробуйте змінити вихідне значення теми на `'dark'`. +У прикладі нижче кнопка "Перемкнути тему" завжди буде світлою, тому що вона **знаходиться поза жодним провайдером теми**, а початкове значенням теми — `'light'`. Спробуйте змінити початкову тему на `'dark'`. @@ -1062,9 +1063,9 @@ function Button({ children, onClick }) { --- -### Часткове перевизначення контексту {/*overriding-context-for-a-part-of-the-tree*/} +### Перевизначення контексту частини дерева {/*overriding-context-for-a-part-of-the-tree*/} -Можливо перевизначити контекст для частини дерева компонентів, обернувши цю частину у провайдер з іншим значенням. +Можливо перевизначити контекст для частини дерева компонентів, обгорнувши цю частину у провайдер з іншим значенням. ```js {3,5} @@ -1188,7 +1189,7 @@ footer { #### Автоматичне вкладення заголовків {/*automatically-nested-headings*/} -Ви можете "накопичувати" інформацію, коли вкладаєте провайдери контексту. У цьому прикладі компонент `Section` відстежує `LevelContext`, який визначає глибину вкладення секцій. Він зчитує `LevelContext` з батьківської секції та передає зі збільшеним на одиницю значенням своїм дочірнім елементам. У підсумку компонент `Heading` може автоматично визначати, який із тегів `

`, `

`, `

`, ... , використовувати в залежності від кількості вкладених компонентів `Section`. +Ви можете "накопичувати" інформацію, коли вкладаєте провайдери контексту один в одного. У цьому прикладі компонент `Section` відстежує `LevelContext`, який визначає глибину вкладення секцій. Він зчитує `LevelContext` із батьківської секції та передає зі збільшеним на одиницю значенням своїм дочірнім елементам. У підсумку компонент `Heading` може автоматично визначати, який із тегів `

`, `

`, `

`, ... , використовувати в залежності від кількості вкладених компонентів `Section`. Перегляньте [детальний приклад](/learn/passing-data-deeply-with-context) цього процесу. @@ -1288,9 +1289,9 @@ export const LevelContext = createContext(0); --- -### Усунення зайвих рендерів при передачі об'єктів і функцій {/*optimizing-re-renders-when-passing-objects-and-functions*/} +### Усунення зайвих рендерів під час передавання об'єктів і функцій {/*optimizing-re-renders-when-passing-objects-and-functions*/} -Ви можете передавати будь-які значення через контекст, включаючи об'єкти та функції. +Ви можете передавати будь-які значення через контекст, включно з об'єктами та функціями. ```js [[2, 10, "{ currentUser, login }"]] function MyApp() { @@ -1309,9 +1310,9 @@ function MyApp() { } ``` -Тут значення контексту є об'єктом JavaScript з двома властивостями, одна з яких є функцією. Щоразу, коли `MyApp` повторно рендериться (наприклад, при оновленні маршруту), це буде *інший* об'єкт, що вказує на *іншу* функцію, тому React доведеться повторно рендерити всі компоненти, глибоко розташовані в дереві, які викликають `useContext(AuthContext)`. +Тут значення контексту є об'єктом JavaScript із двома властивостями, одна з яких є функцією. Щоразу, коли `MyApp` повторно рендериться (наприклад, під час оновлення маршруту), це буде *інший* об'єкт, що вказує на *іншу* функцію, тому React доведеться повторно рендерити всі глибоко розташовані в дереві компоненти, які викликають `useContext(AuthContext)`. -У менших додатках це не є проблемою. Однак немає потреби повторно рендерити компоненти, якщо основні дані, як-от `currentUser`, не змінилися. Щоб оптимізувати роботу React, ви можете обгорнути функцію `login` в [`useCallback`](/reference/react/useCallback) та створення об'єкта в [`useMemo`](/reference/react/useMemo). Це є оптимізацією продуктивності: +У менших застосунках це не є проблемою. Однак немає потреби повторно рендерити компоненти, якщо основні дані, як-от `currentUser`, не змінилися. Щоб оптимізувати роботу React, ви можете обгорнути функцію `login` у [`useCallback`](/reference/react/useCallback), а створення об'єкта — в [`useMemo`](/reference/react/useMemo). Це є оптимізацією продуктивності: ```js {6,9,11,14,17} @@ -1338,51 +1339,51 @@ function MyApp() { } ``` -Як наслідок цієї зміни, навіть якщо `MyApp` потребує повторного рендеру, компоненти, що викликають `useContext(AuthContext)`, не потребуватимуть, якщо `currentUser` не змінився. +Як наслідок цієї зміни, навіть якщо `MyApp` потребує повторного рендеру, компоненти, що викликають `useContext(AuthContext)`, не потребуватимуть його, якщо `currentUser` не змінився. -Дізнайтеся більше про [`useMemo`](/reference/react/useMemo#skipping-re-rendering-of-components) та [`useCallback`](/reference/react/useCallback#skipping-re-rendering-of-components). +Дізнайтеся більше про [`useMemo`](/reference/react/useMemo#skipping-re-rendering-of-components) та [`useCallback`.](/reference/react/useCallback#skipping-re-rendering-of-components) --- -## Вирішення проблем {/*troubleshooting*/} +## Усунення несправностей {/*troubleshooting*/} ### Компонент не бачить значення з провайдера {/*my-component-doesnt-see-the-value-from-my-provider*/} Існує кілька поширених причин, чому це може статися: 1. Ви розміщуєте `` у тому ж компоненті або нижче, ніж компонент, де викликано `useContext()`. Перемістіть `` *вище і зовні* компонента, який викликає `useContext()`. -2. Можливо, ви забули обгорнути свій компонент у ``, або розмістили його в іншій частині дерева, ніж планували. Переконайтесь за допомогою [React DevTools](/learn/react-developer-tools), що ієрархія компонентів налаштована правильно. -3. Можливо, ви зіткнулися з проблемою збірки, через яку `SomeContext`, доступний у провайдері, і `SomeContext`, що використовується споживачем, є різними об'єктами. Це може статися, наприклад, якщо ви використовуєте псевдоніми. Можете перевірити це, присвоївши їх глобальним змінним, як-от `window.SomeContext1` і `window.SomeContext2`, а потім порівняти `window.SomeContext1 === window.SomeContext2` в консолі. Якщо вони не тотожні, виправте цю проблему на рівні збірки. +2. Можливо, ви забули обгорнути свій компонент у `` або розмістили його в іншій, ніж задумали, частині дерева. Переконайтеся за допомогою [React DevTools](/learn/react-developer-tools), що ієрархія компонентів налаштована правильно. +3. Можливо, ви зіткнулися з проблемою збірки, через яку `SomeContext` із компонента-провайдера і `SomeContext` компонента-читача є різними об'єктами. Це може статися, наприклад, якщо ви використовуєте символьні посилання. Можете перевірити це, присвоївши їх глобальним змінним, як-от `window.SomeContext1` і `window.SomeContext2`, а потім порівняти `window.SomeContext1 === window.SomeContext2` в консолі. Якщо вони не тотожні, виправте цю проблему на рівні збірки. -### Я завжди отримую `undefined` з контексту, хоча значення за замовчуванням інше {/*i-am-always-getting-undefined-from-my-context-although-the-default-value-is-different*/} +### Я завжди отримую `undefined` із контексту, хоча початкове значення інше {/*i-am-always-getting-undefined-from-my-context-although-the-default-value-is-different*/} Можливо, у вас є провайдер без `value` у дереві: ```js {1,2} -// 🚩 Не працює: немає властивості value +// 🚩 Не працює: немає пропа value