update browser

This commit is contained in:
2025-03-06 16:09:21 +03:00
parent 1445c4f31f
commit 7484909864
16 changed files with 572 additions and 91 deletions

View File

@@ -0,0 +1,5 @@
---
sidebar_position: 6
---
# Micro frontend

View File

@@ -1,5 +1,5 @@
--- ---
sidebar_position: 6 sidebar_position: 7
--- ---
# Test driven development # Test driven development

39
docs/browser/06-cors.md Normal file
View File

@@ -0,0 +1,39 @@
---
sidebar_position: 6
---
# CORS
**CORS** (Cross-Origin Resource Sharing) — это механизм, который позволяет веб-страницам запрашивать ресурсы с другого домена, отличного от того, с которого была загружена сама страница. Это важно, потому что браузеры по умолчанию блокируют такие запросы из соображений безопасности (это называется политикой одного источника — Same-Origin Policy).
## Как работает CORS:
1. **Запрос с другого источника:**
- Когда веб-страница пытается сделать запрос (например, через `fetch` или `XMLHttpRequest`) к ресурсу на другом домене, браузер автоматически добавляет в запрос заголовок `Origin`. Этот заголовок содержит домен, с которого был отправлен запрос.
2. **Ответ сервера:**
- Сервер, получив запрос, может разрешить или запретить доступ к ресурсу. Если сервер поддерживает CORS, он добавляет в ответ заголовок `Access-Control-Allow-Origin`, указывая, какие домены могут получить доступ к ресурсу.
- Например, если сервер разрешает доступ всем доменам, он может вернуть: \
`Access-Control-Allow-Origin: *` \
Если доступ разрешен только конкретному домену, то:
`Access-Control-Allow-Origin: https://example.com`
3. **Проверка браузером:**
- Браузер проверяет заголовок `Access-Control-Allow-Origin` в ответе сервера. Если значение заголовка совпадает с доменом, с которого был отправлен запрос (или это *), браузер разрешает доступ к данным. В противном случае запрос блокируется, и на странице возникает ошибка CORS.
4. **Предварительные запросы (Preflight):**
- Для некоторых типов запросов (например, с использованием методов, отличных от GET/POST, или с кастомными заголовками), браузер сначала отправляет предварительный запрос (OPTIONS), чтобы проверить, поддерживает ли сервер CORS и разрешает ли он такие запросы.
- Сервер должен ответить на этот запрос, указав разрешенные методы, заголовки и другие параметры.
## Пример
- Веб-страница на https://example.com делает запрос к API на https://api.example.com.
- Браузер отправляет запрос с заголовком: `Origin: https://example.com`
- Сервер отвечает: `Access-Control-Allow-Origin: https://example.com`
- Браузер проверяет заголовок и разрешает доступ к данным.
## Основные заголовки CORS:
- **Origin:** Указывает домен, с которого отправлен запрос.
- **Access-Control-Allow-Origin:** Указывает, какие домены могут получить доступ к ресурсу.
- **Access-Control-Allow-Methods:** Указывает разрешенные HTTP-методы (например, GET, POST).
- **Access-Control-Allow-Headers:** Указывает разрешенные заголовки в запросе.
- **Access-Control-Allow-Credentials:** Указывает, можно ли отправлять куки или другие учетные данные.
## Важно:
CORS работает только в браузерах. Серверные приложения (например, на Node.js или Python) не ограничены политикой CORS.
Если сервер не настроен для поддержки CORS, браузер заблокирует запрос, даже если сервер возвращает данные.

View File

@@ -3,111 +3,134 @@ sidebar_position: 6
--- ---
# Область видимости переменных, замыкание # Область видимости переменных, замыкание
Источник: [https://learn.javascript.ru/closure](https://learn.javascript.ru/closure) Источник: DeepSeek
Доп. источник: [https://learn.javascript.ru/closure](https://learn.javascript.ru/closure)
## Блоки кода ## Область видимости (scope)
Если переменная объявлена внутри блока кода `{...}`, то она видна только внутри этого блока. В JavaScript **область видимости (scope)** определяет, где переменные, функции и другие идентификаторы могут быть использованы в коде. Понимание области видимости важно для написания корректного и предсказуемого кода. В JavaScript есть несколько типов областей видимости:
С помощью блоков `{...}` мы можем изолировать часть кода, выполняющую свою собственную задачу, с переменными, принадлежащими только ей
Для `if`, `for`, `while` и т.д. переменные, объявленные в блоке кода `{...}`, также видны только внутри
## Вложенные функции 1. **Глобальная область видимости (Global Scope)** \
Функция называется «вложенной», когда она создаётся внутри другой функции. Переменные, объявленные вне всех функций или блоков, находятся в глобальной области видимости. Они доступны из любого места в коде.
Она может получить доступ к внешним переменным. 2. **Локальная область видимости (Function Scope)** \
Вложенная функция может быть возвращена: либо в качестве свойства нового объекта (если внешняя функция создаёт объект с методами), либо сама по себе. И затем может быть использована в любом месте. Не важно где, она всё так же будет иметь доступ к тем же внешним переменным. Переменные, объявленные внутри функции, доступны только внутри этой функции. Это называется function scope.
3. **Блочная область видимости (Block Scope)** \
С появлением let и const в ES6 появилась блочная область видимости. Переменные, объявленные внутри блока (например, внутри {}), доступны только внутри этого блока. \
Обратите внимание, что var не имеет блочной области видимости
4. **Лексическая область видимости (Lexical Scope)** \
JavaScript использует лексическую (статическую) область видимости. Это означает, что область видимости определяется во время написания кода, а не во время выполнения. Вложенные функции имеют доступ к переменным из внешних функций.
5. **Область видимости модулей (Module Scope)**
В ES6 появились модули, которые имеют свою собственную область видимости. Переменные, объявленные в модуле, не доступны извне, если они не экспортированы.
6. **Цепочка областей видимости (Scope Chain)**
Когда JavaScript ищет переменную, он сначала проверяет текущую область видимости, затем переходит к внешним областям, пока не достигнет глобальной области. Если переменная не найдена, возникает ошибка.
7. **Замыкания (Closures)**
Замыкание — это функция, которая запоминает свое лексическое окружение даже после того, как внешняя функция завершила выполнение. Это возможно благодаря области видимости.
## Лексическое окружение - **Глобальная область видимости:** переменные доступны везде.
- **Локальная (function scope):** переменные доступны только внутри функции.
- **Блочная (block scope):** переменные доступны только внутри блока ({}), если объявлены через let или const.
- **Лексическая область видимости:** вложенные функции имеют доступ к переменным из внешних функций.
- **Модульная область видимости:** переменные в модулях изолированы.
#### Переменные
В JavaScript у каждой выполняемой функции, блока кода `{...}` и скрипта есть связанный с ними внутренний (скрытый) объект, называемый ***лексическим окружением** `LexicalEnvironment`.
Объект лексического окружения состоит из двух частей: ## Замыкание (closure)
1. **Environment Record** объект, в котором как свойства хранятся все локальные переменные (а также некоторая другая информация, такая как значение this). **Замыкание (closure)** в JavaScript — это мощный механизм, который позволяет функциям "запоминать" свое лексическое окружение (область видимости), даже после того, как внешняя функция завершила выполнение. Замыкания часто используются для создания приватных переменных, реализации функций высшего порядка и других паттернов программирования.
2. Ссылка на **внешнее лексическое окружение** то есть то, которое соответствует коду снаружи (снаружи от текущих фигурных скобок).
**«Переменная» это просто свойство специального внутреннего объекта: `Environment Record`.** \ ### Как работает замыкание?
**«Получить или изменить переменную», означает, «получить или изменить свойство этого объекта».** Когда функция создается, она запоминает ссылку на свое лексическое окружение (все переменные, которые были доступны в момент ее создания). Даже если внешняя функция завершила выполнение, внутренняя функция сохраняет доступ к переменным из этого окружения.
- Переменная это свойство специального внутреннего объекта, связанного с текущим выполняющимся блоком/функцией/скриптом. ### Пример замыкания
- Работа с переменными это на самом деле работа со свойствами этого объекта.
#### Function Declaration
**Разница заключается в том, что Function Declaration мгновенно инициализируется полностью.**
Когда создается лексическое окружение, Function Declaration сразу же становится функцией, готовой к использованию (в отличие от `let`, который до момента объявления не может быть использован).
Поэтому мы можем вызвать функцию, объявленную как Function Declaration, до самого её объявления.
Такое поведение касается только Function Declaration, а не Function Expression, в которых мы присваиваем функцию переменной.
#### Внутреннее и внешнее лексическое окружение
Когда запускается функция, в начале ее вызова автоматически создается новое лексическое окружение для хранения локальных переменных и параметров вызова.
![](images/06-closure-1.png)
В процессе вызова функции у нас есть два лексических окружения: внутреннее (для вызываемой функции) и внешнее (глобальное):
- Внутреннее лексическое окружение соответствует текущему выполнению say.\
В нём находится одна переменная name, параметр функции. Мы вызываем say("John"), так что значение переменной name равно "John".
- Внешнее лексическое окружение это глобальное лексическое окружение.\
В нём находятся переменная phrase и сама функция.
У внутреннего лексического окружения есть ссылка на внешнее `outer`.
**Когда код хочет получить доступ к переменной сначала происходит поиск во внутреннем лексическом окружении, затем во внешнем, затем в следующем и так далее, до глобального.**
Если переменная не была найдена, это будет ошибкой в строгом режиме (`use strict`). Без строгого режима, для обратной совместимости, присваивание несуществующей переменной создаёт новую глобальную переменную с таким же именем.
#### Возврат функции
```js ```js
function makeCounter() { function outer() {
let count = 0; let outerVar = "Я из внешней функции";
function inner() {
console.log(outerVar); // Используем переменную из внешней функции
}
return inner;
}
const closureFunc = outer(); // outer завершила выполнение
closureFunc(); // "Я из внешней функции" — inner помнит outerVar
```
Здесь:
1. Функция `outer` создает переменную `outerVar`.
2. Функция `inner` использует эту переменную.
3. Когда outer завершает выполнение, она возвращает `inner`.
4. Переменная `closureFunc` теперь содержит функцию `inner`, которая сохраняет доступ к `outerVar`.
### Почему это работает?
JavaScript использует **лексическую область видимости (lexical scoping)**. Это означает, что область видимости функции определяется в момент ее создания, а не в момент вызова. Внутренняя функция (`inner`) "замыкается" на переменные из внешней функции (`outer`), даже если внешняя функция уже завершила выполнение.
### Практическое применение замыканий
1. **Приватные переменные** \
Замыкания позволяют создавать приватные переменные, которые недоступны извне.
```js
function createCounter() {
let count = 0; // Приватная переменная
return function() { return function() {
return count++; count++;
return count;
}; };
} }
let counter = makeCounter(); const counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3
``` ```
В начале каждого вызова makeCounter() создается новый объект лексического окружения, в котором хранятся переменные для конкретного запуска makeCounter. Здесь переменная `count` недоступна извне, но функция-счетчик может изменять и возвращать ее значение.
Таким образом, мы имеем два вложенных лексических окружения, как в примере выше: 2. **Функции высшего порядка** \
![](images/06-closure-2.png) Замыкания часто используются в функциях высшего порядка, таких как `map`, `filter`, `reduce`.
Отличие заключается в том, что во время выполнения makeCounter() создается крошечная вложенная функция, состоящая всего из одной строки: return count++. Мы ее еще не запускаем, а только создаем. ```js
function createMultiplier(multiplier) {
return function(number) {
return number * multiplier;
};
}
Все функции помнят лексическое окружение, в котором они были созданы. Технически здесь нет никакой магии: все функции имеют скрытое свойство [[Environment]], которое хранит ссылку на лексическое окружение, в котором была создана функция: const double = createMultiplier(2);
![](images/06-closure-3.png) console.log(double(5)); // 10
```
Здесь `createMultiplier` возвращает функцию, которая "запоминает" значение `multiplier`.
Таким образом, counter.[[Environment]] имеет ссылку на \{count: 0} лексического окружения. Так функция запоминает, где она была создана, независимо от того, где она вызывается. Ссылка на [[Environment]] устанавливается один раз и навсегда при создании функции. 3. **Модули и инкапсуляция** \
Замыкания позволяют создавать модули с приватными методами и переменными.
```js
const module = (function() {
let privateVar = "Я приватная";
Впоследствии, при вызове counter(), для этого вызова создается новое лексическое окружение, а его внешняя ссылка на лексическое окружение берется из counter.[[Environment]]: function privateMethod() {
![](images/06-closure-4.png) console.log(privateVar);
Теперь, когда код внутри counter() ищет переменную count, он сначала ищет ее в собственном лексическом окружении (пустом, так как там нет локальных переменных), а затем в лексическом окружении внешнего вызова makeCounter(), где находит count и изменяет ее. }
***Переменная обновляется в том лексическом окружении, в котором она существует.*** return {
![](images/06-closure-5.png) publicMethod: function() {
Если мы вызовем counter() несколько раз, то в одном и том же месте переменная count будет увеличена до 2, 3 и т.д. privateMethod();
}
};
})();
💥 **Замыкания** module.publicMethod(); // "Я приватная"
console.log(module.privateVar); // undefined (недоступно)
```
**Замыкание** это функция, которая запоминает свои внешние переменные и может получить к ним доступ. В некоторых языках это невозможно, или функция должна быть написана специальным образом, чтобы получилось замыкание. Но, как было описано выше, в JavaScript, все функции изначально являются замыканиями. 4. **Колбэки и асинхронный код** \
Замыкания часто используются в асинхронном коде, чтобы сохранить состояние.
Здесь функция внутри setTimeout "запоминает" значение name.
```js
function delayedGreeting(name) {
setTimeout(function() {
console.log(`Привет, ${name}!`);
}, 1000);
}
delayedGreeting("Алексей"); // Через 1 секунду: "Привет, Алексей!"
```
Здесь функция внутри setTimeout "запоминает" значение name.
То есть они автоматически запоминают, где были созданы, с помощью скрытого свойства `[[Environment]]`, и все они могут получить доступ к внешним переменным. ### Как избежать утечек памяти?
Замыкания могут приводить к утечкам памяти, если они сохраняют ссылки на большие объекты, которые больше не используются. Чтобы избежать этого:
Когда на собеседовании фронтенд-разработчику задают вопрос: «что такое замыкание?», правильным ответом будет определение замыкания и объяснения того факта, что все функции в JavaScript являются замыканиями, и, может быть, несколько слов о технических деталях: свойстве `[[Environment]]` и о том, как работает лексическое окружение. - Убедитесь, что замыкания не сохраняют ненужные данные.
- Используйте null для очистки ссылок, когда они больше не нужны.
Есть только одно исключение, когда функция создаётся с использованием `new Function`, в её `[[Environment]]` записывается ссылка не на внешнее лексическое окружение, в котором она была создана, а на глобальное. Поэтому такая функция имеет доступ только к глобальным переменным.
## Сборка мусора
Обычно лексическое окружение удаляется из памяти вместе со всеми переменными после завершения вызова функции. Это связано с тем, что на него нет ссылок. Как и любой объект JavaScript, оно хранится в памяти только до тех пор, пока к нему можно обратиться.
Однако если существует вложенная функция, которая все еще доступна после завершения функции, то она имеет свойство `[[Environment]]`, ссылающееся на лексическое окружение.
В этом случае лексическое окружение остается доступным даже после завершения работы функции.
Объект лексического окружения исчезает, когда становится недоступным (как и любой другой объект). Другими словами, он существует только до тех пор, пока на него ссылается хотя бы одна вложенная функция.
#### Оптимизация на практике
Но на практике движки JavaScript пытаются это оптимизировать. Они анализируют использование переменных и, если легко по коду понять, что внешняя переменная не используется она удаляется.
***Одним из важных побочных эффектов в V8 (Chrome, Edge, Opera) является то, что такая переменная становится недоступной при отладке.***

View File

@@ -0,0 +1,68 @@
---
sidebar_position: 7
---
# Event loop
Источник: DeepSeek \
Видеоразбор: [JavaScript - Event Loop | Асинхронность, Web API, Очереди (макро/микро)задач, Отрисовка кадров](https://www.youtube.com/watch?v=YTLXrji4DJc)
Event Loop (цикл событий) — это механизм, который позволяет JavaScript выполнять асинхронные операции, несмотря на то, что сам язык является однопоточным. Он отвечает за обработку событий, вызовов колбэков и выполнение задач в правильном порядке.
## Основные компоненты Event Loop
1. **Call Stack (стек вызовов):**
- Это структура данных, которая отслеживает текущие выполняемые функции.
- Когда функция вызывается, она добавляется в стек. Когда функция завершается, она удаляется из стека.
- JavaScript однопоточный, поэтому в один момент времени может выполняться только одна задача.
2. **Web APIs (или Browser APIs):**
- Это API, предоставляемые браузером (или средой выполнения, например, Node.js), которые позволяют выполнять асинхронные операции, такие как `setTimeout`, `fetch`, `XMLHttpRequest`, обработка событий (клики, таймеры и т.д.).
- Когда асинхронная операция запускается, она передается в Web API, и основной поток JavaScript продолжает выполнение.
3. **Callback Queue (очередь колбэков):**
- Когда асинхронная операция завершается, ее колбэк помещается в очередь колбэков.
- Примеры: колбэки из `setTimeout`, обработчики событий.
4. **Microtask Queue (очередь микрозадач):**
- Это отдельная очередь для микрозадач, таких как промисы (`Promise`) и `MutationObserver`.
- Микрозадачи имеют приоритет над задачами из Callback Queue.
5. **Event Loop:**
- Это бесконечный цикл, который проверяет, пуст ли Call Stack.
- Если Call Stack пуст, Event Loop берет задачи из Callback Queue и Microtask Queue и помещает их в Call Stack для выполнения.
## Как работает Event Loop
1. Синхронный код:
- Весь синхронный код выполняется сразу, попадая в Call Stack.
2. Асинхронный код:
- Когда встречается асинхронная операция (например, `setTimeout` или `fetch`), она передается в Web API, и основной поток продолжает выполнение.
- После завершения асинхронной операции ее колбэк помещается в Callback Queue (или Microtask Queue, если это промис).
3. Обработка очередей:
- Когда Call Stack пуст, Event Loop сначала проверяет Microtask Queue.
- Все микрозадачи (например, колбэки промисов) выполняются до того, как Event Loop перейдет к Callback Queue.
- После выполнения всех микрозадач Event Loop берет задачи из Callback Queue и помещает их в Call Stack.
## Пример работы Event Loop
```js
console.log("Start");
setTimeout(() => {
console.log("Timeout");
}, 0);
Promise.resolve().then(() => {
console.log("Promise");
});
console.log("End");
```
#### Вывод:
```
Start
End
Promise
Timeout
```
#### Объяснение:
1. Сначала выполняется синхронный код: `console.log("Start")` и `console.log("End")`.
2. `setTimeout` передается в Web API, а его колбэк попадает в Callback Queue.
3. Промис сразу резолвится, и его колбэк попадает в Microtask Queue.
4. После завершения синхронного кода Event Loop сначала выполняет микрозадачи (колбэк промиса), а затем переходит к Callback Queue (колбэк `setTimeout`).
Event Loop позволяет JavaScript эффективно обрабатывать асинхронные операции, несмотря на однопоточность. Он управляет порядком выполнения задач, используя Call Stack, Web APIs, Callback Queue и Microtask Queue. Понимание этого механизма важно для написания эффективного и предсказуемого асинхронного кода.

View File

@@ -57,4 +57,4 @@ Reconciliation — это процесс сравнения старого и н
## Итог ## Итог
- **Virtual DOM** — это оптимизированная копия реального DOM, которая позволяет React быстро обновлять интерфейс. - **Virtual DOM** — это оптимизированная копия реального DOM, которая позволяет React быстро обновлять интерфейс.
- **Reconciliation** — это процесс сравнения старого и нового Virtual DOM для определения минимального набора изменений. - **Reconciliation** — это процесс сравнения старого и нового Virtual DOM для определения минимального набора изменений.
- Вместе эти механизмы делают React быстрым, эффективным и удобным для разработки сложных интерфейсов. Вместе эти механизмы делают React быстрым, эффективным и удобным для разработки сложных интерфейсов.

View File

@@ -3,3 +3,32 @@ sidebar_position: 3
--- ---
# Жизненный цикл компонента # Жизненный цикл компонента
Жизненный цикл компонента в React описывает этапы, через которые проходит компонент от момента его создания до удаления из DOM. Эти этапы включают инициализацию, обновление и удаление компонента. React предоставляет методы жизненного цикла, которые позволяют разработчикам управлять поведением компонента на каждом этапе.
## Основные этапы жизненного цикла компонента:
1. **Монтирование (Mounting):**
Компонент создается и вставляется в DOM.
- `constructor(props)`: Вызывается до того, как компонент будет смонтирован. Используется для инициализации состояния и привязки методов.
- `static getDerivedStateFromProps(props, state)`: Вызывается непосредственно перед рендерингом, как при монтировании, так и при обновлении. Позволяет компоненту обновить состояние на основе изменений в пропсах.
- `render()`: Метод, который возвращает JSX. Он отвечает за отображение компонента в DOM.
- `componentDidMount()`: Вызывается сразу после монтирования компонента в DOM. Здесь можно выполнять запросы к серверу, подписываться на события или работать с DOM.
2. **Обновление (Updating):**
Компонент обновляется при изменении состояния или пропсов.
- `static getDerivedStateFromProps(props, state)`: Вызывается перед рендерингом при обновлении компонента.
- `shouldComponentUpdate(nextProps, nextState)`: Позволяет оптимизировать производительность, определяя, нужно ли перерисовывать компонент. Возвращает true или false.
- `render()`: Перерисовывает компонент, если это необходимо.
- `getSnapshotBeforeUpdate(prevProps, prevState)`: Вызывается прямо перед тем, как изменения из виртуального DOM будут применены к реальному DOM. Позволяет получить информацию о DOM перед обновлением.
- `componentDidUpdate(prevProps, prevState, snapshot)`: Вызывается после обновления компонента. Здесь можно выполнять дополнительные действия, такие как запросы к серверу или обновление состояния.
3. **Размонтирование (Unmounting):**
Компонент удаляется из DOM.
- `componentWillUnmount()`: Вызывается перед удалением компонента из DOM. Здесь можно выполнять очистку, такую как отмена таймеров, отписка от событий или отмена сетевых запросов.
4. **Обработка ошибок (Error Handling):**
React также предоставляет методы для обработки ошибок, которые происходят в компонентах.
- `static getDerivedStateFromError(error)`: Вызывается после возникновения ошибки в дочернем компоненте. Позволяет обновить состояние для отображения запасного UI.
- `componentDidCatch(error, info)`: Вызывается после возникновения ошибки. Позволяет логировать ошибки или выполнять другие действия.
С появлением React Hooks в версии 16.8, функциональные компоненты также получили возможность использовать аналогичные методы жизненного цикла с помощью хуков, таких как `useEffect`. Это сделало функциональные компоненты более мощными и гибкими.
Таким образом, жизненный цикл компонента в React позволяет разработчикам контролировать поведение компонента на всех этапах его существования, что делает React мощным инструментом для создания динамических и отзывчивых пользовательских интерфейсов.

View File

@@ -3,3 +3,63 @@ sidebar_position: 4
--- ---
# Состояние и пропсы компонентов # Состояние и пропсы компонентов
В React состояние (state) и пропсы (props) — это два основных способа управления данными в компонентах. Они позволяют
компонентам быть динамичными и реагировать на изменения данных. Однако они используются в разных ситуациях и имеют свои
особенности.
- **Props** — это данные, которые передаются в компонент извне. Они неизменяемы.
- **State** — это внутренние данные компонента, которые могут изменяться. Состояние делает компонент динамичным и
реактивным.
## Props (Properties)
Пропсы — это входные данные, которые передаются в компонент извне (обычно от родительского компонента). Они
неизменяемы (immutable), то есть компонент не может изменять свои пропсы, а только читать их.
**Основные особенности:**
1. **Передача данных сверху вниз:** Пропсы передаются от родительского компонента к дочернему.
2. **Неизменяемость:** Компонент не может изменять свои пропсы. Они доступны только для чтения.
3. **Использование:** Пропсы используются для передачи данных, конфигурации или callback-функций в компонент.
## State (Состояние)
Состояние — это внутренние данные компонента, которые могут изменяться со временем. Состояние управляется самим
компонентом и используется для хранения информации, которая может изменяться в результате пользовательских действий,
сетевых запросов или других событий.
**Основные особенности:**
1. **Локальность:** Состояние принадлежит конкретному компоненту и не может быть доступно извне (если не передано через
пропсы).
2. **Изменяемость:** Состояние можно изменять с помощью метода `setState` (в классовых компонентах) или функции
обновления
состояния (в функциональных компонентах с использованием хука `useState`).
3. **Реактивность:** При изменении состояния React автоматически перерисовывает компонент.
## Различия между State и Props
| Характеристика | Props | State |
|-----------------|-------------------------------------------|-----------------------------------------------|
| Источник данных | Передаются извне (родительский компонент) | Управляются внутри компонента |
| Изменяемость | Неизменяемы (read-only) | Изменяемы (через `setState` или `useState`) |
| Использование | Для передачи данных и callback-функций | Для хранения данных, которые могут изменяться |
| Доступность | Доступны в дочерних компонентах | Локальны для компонента |
## Когда использовать Props, а когда State?
- Props:
- Когда данные передаются от родительского компонента к дочернему.
- Когда данные не должны изменяться внутри компонента.
- Для передачи callback-функций, которые могут изменять состояние родительского компонента.
- State:
- Когда данные должны изменяться внутри компонента (например, в ответ на действия пользователя).
- Для хранения временных данных, таких как ввод пользователя, состояние загрузки и т.д.
## Взаимодействие State и Props
Часто состояние родительского компонента передается в дочерний компонент через пропсы. Если дочерний компонент должен
изменить эти данные, он может вызвать callback-функцию, переданную через пропсы, которая изменит состояние родительского
компонента.

View File

@@ -3,3 +3,78 @@ sidebar_position: 5
--- ---
# Базовые хуки React # Базовые хуки React
React предоставляет несколько основных хуков, которые позволяют использовать состояние и другие возможности React в функциональных компонентах. Вот основные хуки:
1. **useState:**
- Позволяет добавлять состояние в функциональный компонент.
- Возвращает массив, где первый элемент — текущее значение состояния, а второй — функция для его обновления.
```js
const [count, setCount] = useState(0);
```
2. **useEffect:**
- Позволяет выполнять побочные эффекты в функциональных компонентах (например, запросы к API, подписки, ручное изменение DOM).
- Принимает два аргумента: функцию с эффектом и массив зависимостей (опционально).
```js
useEffect(() => {
document.title = `Вы нажали ${count} раз`;
}, [count]);
```
3. **useContext:**
- Позволяет использовать контекст в функциональных компонентах.
- Принимает объект контекста (созданный с помощью `React.createContext`) и возвращает текущее значение контекста.
```js
const value = useContext(MyContext);
```
4. **useReducer:**
- Альтернатива `useState` для управления сложным состоянием.
- Принимает редюсер (функцию, которая определяет, как состояние должно обновляться) и начальное состояние.
- Возвращает текущее состояние и функцию `dispatch` для отправки действий.
```js
const [state, dispatch] = useReducer(reducer, initialState);
```
5. **useCallback:**
- Возвращает мемоизированную версию колбэка, которая изменяется только при изменении зависимостей.
- Полезен для оптимизации производительности, когда колбэк передается в дочерние компоненты.
```js
const memoizedCallback = useCallback(() => {
doSomething(a, b);
}, [a, b]);
```
6. **useMemo:**
- Возвращает мемоизированное значение, которое пересчитывается только при изменении зависимостей.
- Полезен для оптимизации вычислений, которые требуют больших затрат ресурсов.
```js
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
```
7. **useRef:**
- Возвращает изменяемый объект, свойство `.current` которого инициализируется переданным аргументом.
- Используется для хранения мутабельных значений, которые не вызывают ререндер при изменении.
- Также может использоваться для получения ссылок на DOM-элементы.
```js
const inputRef = useRef(null);
```
8. **useImperativeHandle:**
- Позволяет настроить экземпляр значения, которое будет доступно при использовании `ref`.
- Обычно используется вместе с `forwardRef`.
```js
useImperativeHandle(ref, () => ({
focus() {
inputRef.current.focus();
}
}));
```
9. **useLayoutEffect:**
- Похож на `useEffect`, но выполняется синхронно после всех изменений DOM, но до того, как браузер отрисует изменения.
- Используется для измерений DOM или других операций, которые должны быть выполнены до отрисовки.
```js
useLayoutEffect(() => {
// Логика, которая должна выполниться до отрисовки
}, [dependencies]);
```
10. useDebugValue:
- Используется для отладки пользовательских хуков.
- Позволяет отображать метку для пользовательских хуков в инструментах разработчика React.
```js
useDebugValue(isOnline ? 'Online' : 'Offline');
```

View File

@@ -3,3 +3,40 @@ sidebar_position: 6
--- ---
# Что такое HOC # Что такое HOC
Higher-Order Components (HOC) — это продвинутая техника в React для повторного использования логики компонентов. HOC — это функция, которая принимает компонент и возвращает новый компонент с дополнительными свойствами или поведением. Это похоже на паттерн декоратора в программировании.
## Основные идеи HOC:
1. **Принимает компонент и возвращает новый компонент:**
- HOC не изменяет оригинальный компонент, а создает новый, оборачивая его и добавляя новую функциональность.
2. **Используется для повторного использования логики:**
- HOC позволяет вынести общую логику (например, загрузку данных, управление состоянием, логику авторизации) в отдельную функцию, которую можно применять к разным компонентам.
3. **Не изменяет оригинальный компонент:**
- HOC создает новый компонент, оставляя оригинальный неизменным.
## Преимущества HOC:
1. Повторное использование кода:
- Логика загрузки данных, управление состоянием и другие общие задачи могут быть вынесены в HOC и использованы в разных компонентах.
2. Разделение ответственности:
- Компоненты остаются простыми и сосредоточены только на отображении данных, а HOC отвечает за логику.
3. Гибкость:
- HOC можно комбинировать, создавая сложные цепочки функциональности.
## Недостатки HOC:
1. Сложность отладки:
- HOC добавляют уровень вложенности в дерево компонентов, что может усложнить отладку.
2. Проблемы с именованием пропсов:
- Если несколько HOC передают одинаковые пропсы, могут возникнуть конфликты.
3. Усложнение кода:
- Чрезмерное использование HOC может сделать код менее читаемым и понятным.
## Альтернативы HOC:
С появлением хуков (например, `useState`, `useEffect`, `useContext`), многие задачи, которые раньше решались с помощью HOC, теперь можно реализовать с помощью пользовательских хуков. Это часто делает код более понятным и менее сложным.
## Когда использовать HOC:
- Если вам нужно добавить одну и ту же логику к нескольким компонентам.
- Если вы работаете с классовыми компонентами (хуки доступны только в функциональных компонентах).
- Если вы предпочитаете паттерн декоратора.
В остальных случаях, особенно в новых проектах, рекомендуется использовать хуки, так как они проще и удобнее.

View File

@@ -3,3 +3,110 @@ sidebar_position: 7
--- ---
# Хуки оптимизации и кэширования # Хуки оптимизации и кэширования
## useCallback
`useCallback` — это хук в React, который используется для мемоизации функций. Он помогает оптимизировать производительность компонентов, особенно когда речь идет о передаче функций в дочерние компоненты или их использование в зависимостях других хуков, таких как `useEffect`.
### Зачем нужен useCallback?
1. **Оптимизация рендеринга дочерних компонентов:**
- В React компоненты перерисовываются, если изменяются их пропсы или состояние.
- Если вы передаете функцию как пропс в дочерний компонент, и эта функция создается заново при каждом рендере родительского компонента, то дочерний компонент будет перерисовываться даже если это не нужно.
- `useCallback` позволяет сохранить ссылку на одну и ту же функцию между рендерами, если её зависимости не изменились. Это предотвращает ненужные перерисовки дочерних компонентов.
2. **Избежание лишних вызовов `useEffect`:**
- Если функция используется в зависимостях `useEffect`, то каждый раз, когда функция создается заново, `useEffect` будет срабатывать снова.
- useCallback позволяет избежать этого, сохраняя стабильную ссылку на функцию.
3. **Улучшение производительности:**
- Создание функций в JavaScript — это операция, которая занимает время и память. Если функция не изменяется, то нет смысла создавать её заново при каждом рендере.
### Как работает useCallback?
`useCallback` принимает два аргумента:
1. Функция, которую нужно мемоизировать.
2. Массив зависимостей.
Хук возвращает мемоизированную версию функции, которая изменяется только тогда, когда изменяются значения в массиве зависимостей.
### Когда использовать useCallback?
- Когда функция передается в качестве пропса в дочерний компонент, который оптимизирован с помощью `React.memo`.
- Когда функция используется в зависимостях других хуков, таких как `useEffect`.
- Когда создание функции является дорогостоящей операцией.
### Когда не нужно использовать useCallback?
- Если функция не передается в дочерние компоненты или не используется в зависимостях других хуков.
- Если функция простая и её создание не влияет на производительность.
Использование `useCallback` должно быть обоснованным, так как избыточное применение может усложнить код и не принести значительной пользы.
## React.memo
**React.memo** — это функция высшего порядка (Higher-Order Component, HOC), которая используется для оптимизации производительности функциональных компонентов в React. Она позволяет избежать лишних рендеров компонента, если его пропсы не изменились.
### Как работает React.memo?
Когда вы оборачиваете компонент в `React.memo`, React запоминает (мемоизирует) результат его рендеринга. При последующих рендерах React сравнивает текущие пропсы с предыдущими. Если пропсы не изменились, React использует закэшированный результат рендеринга, вместо того чтобы выполнять рендер компонента заново.
### Кастомная функция сравнения:
По умолчанию React.memo поверхностно сравнивает пропсы (с использованием Object.is). Если вам нужно более сложное сравнение, вы можете передать вторым аргументом кастомную функцию сравнения:
```js
const MyComponent = React.memo(
function MyComponent(props) {
// Логика компонента
},
(prevProps, nextProps) => {
// Возвращает true, если пропсы считаются равными (рендер не нужен)
// Возвращает false, если пропсы изменились (рендер нужен)
return prevProps.value === nextProps.value;
}
);
```
### Когда использовать React.memo?
1. **Компоненты, которые часто рендерятся с одинаковыми пропсами:**
- Если компонент часто рендерится, но его пропсы редко меняются, React.memo поможет избежать лишних рендеров.
2. **Тяжелые компоненты:**
- Если компонент выполняет сложные вычисления или рендерит большое количество элементов, `React.memo` может значительно улучшить производительность.
3. **Компоненты, которые получают стабильные пропсы:**
- Если пропсы компонента редко меняются (например, данные из контекста или мемоизированные значения), `React.memo` будет полезен.
### Когда не нужно использовать React.memo?
1. **Легковесные компоненты:**
- Если компонент простой и его рендер не требует значительных ресурсов, использование `React.memo` может быть избыточным.
2. **Компоненты, пропсы которых часто меняются:**
- Если пропсы компонента часто меняются, `React.memo` не принесет пользы, так как компонент всё равно будет перерисовываться.
3. **Компоненты с побочными эффектами:**
- Если компонент зависит от побочных эффектов (например, от глобального состояния), `React.memo` может не сработать как ожидается.
### Важные моменты:
- `React.memo` работает только с функциональными компонентами.
- Он не предотвращает рендеры, вызванные изменением состояния внутри компонента.
- Используйте `React.memo` только там, где это действительно необходимо, чтобы не усложнять код без нужды.
## useMemo
Хук `useMemo` в React используется для мемоизации (запоминания) значений. Он позволяет оптимизировать производительность, избегая повторных вычислений значений, которые не изменились между рендерами. Это особенно полезно для дорогостоящих вычислений или операций, которые зависят от определенных данных.
### Как работает useMemo?
useMemo принимает два аргумента:
1. **Функция, которая возвращает значение** (эта функция будет выполнена только при изменении зависимостей).
2. **Массив зависимостей** — список значений, при изменении которых функция будет выполнена заново.
Хук возвращает мемоизированное значение, которое будет пересчитано только при изменении зависимостей.
```js
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
```
### Когда использовать useMemo?
1. **Дорогостоящие вычисления:**
- Если у вас есть сложные вычисления, которые занимают много времени (например, сортировка больших массивов, математические операции и т.д.), `useMemo` поможет избежать их повторного выполнения.
2. **Оптимизация рендеров:**
- Если значение используется в рендере компонента и зависит от пропсов или состояния, `useMemo` предотвратит лишние рендеры, если зависимости не изменились.
3. **Передача мемоизированных значений в дочерние компоненты:**
- Если вы передаете вычисленное значение как пропс в дочерний компонент, `useMemo` поможет избежать лишних рендеров дочернего компонента.
### Когда не нужно использовать useMemo?
1. **Легковесные вычисления:**
- Если вычисления простые и не требуют значительных ресурсов, использование `useMemo` может быть избыточным.
2. **Часто изменяющиеся зависимости:**
- Если зависимости часто меняются, `useMemo` не принесет пользы, так как значение будет пересчитываться при каждом рендере.
3. **Не связанные с рендером значения:**
- Если значение не используется в рендере или не влияет на производительность, `useMemo` не нужен.
### Важные моменты:
- `useMemo` не гарантирует, что функция не будет выполнена. Она может быть вызвана React для "подстраховки" (например, при изменении приоритетов рендеринга).
- Используйте `useMemo` только там, где это действительно необходимо, чтобы не усложнять код без нужды.

View File

@@ -1,6 +1,6 @@
{ {
"label": "Tasks", "label": "Tasks",
"position": 11, "position": 12,
"link": { "link": {
"type": "generated-index" "type": "generated-index"
} }

View File

@@ -0,0 +1,27 @@
---
sidebar_position: 1
---
# Метод оценки сложности алгоритма O(n)
Метод оценки сложности алгоритма **O(n)** используется для анализа времени выполнения алгоритма в зависимости от размера входных данных. Обозначение **O(n)** означает, что время выполнения алгоритма растёт линейно с увеличением размера входных данных.
## Пример на JavaScript:
Рассмотрим простой пример алгоритма, который проходит по всем элементам массива и выполняет какую-то операцию (например, вывод в консоль):
```js
function printArrayElements(arr) {
for (let i = 0; i < arr.length; i++) {
console.log(arr[i]);
}
}
const array = [1, 2, 3, 4, 5];
printArrayElements(array);
```
## Объяснение:
1. **Цикл `for`:** В этом примере цикл `for` проходит по каждому элементу массива `arr`. Количество итераций цикла равно длине массива `n`.
2. **Линейная зависимость:** Если массив увеличивается в размере (например, в 2 раза), то количество итераций цикла также увеличивается в 2 раза. Это означает, что время выполнения алгоритма растёт линейно с увеличением размера входных данных.
3. **Сложность O(n):** Таким образом, сложность этого алгоритма оценивается как **O(n)**, где `n` — это количество элементов в массиве.
## Заключение:
Метод оценки сложности **O(n)** помогает понять, как будет вести себя алгоритм при увеличении объёма данных. В данном случае, если массив станет очень большим, время выполнения алгоритма будет пропорционально увеличиваться.

1
docs/testing/.gitkeep Normal file
View File

@@ -0,0 +1 @@
empty

View File

@@ -0,0 +1,7 @@
{
"label": "Testing",
"position": 11,
"link": {
"type": "generated-index"
}
}

3
docs/testing/index.md Normal file
View File

@@ -0,0 +1,3 @@
---
sidebar_position: 1
---