React Flashcards

1
Q

Назовите минимум 2 правила Хуков React

A

это один из продвинутых способов для повторного использования логики.

Это функция, которая на вход принимает одну компоненту, и выкидывает эту же компоненту, но обернутую в какую-то контейнерную компоненту.

Это нужно, чтобы переиспользовать логику и не дублировать код. В контейнерной компоненте сидит логика, и эту логику могут переиспользовать компоненты множество раз(компоненты, которые принимает та функция на вход)

С1 => function()=> C0(C1)(обернулась)

С2 => function()=> C0(C2)(обернулась)

С3 => function()=> C0(C3)(обернулась)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

Компонент высшего порядка (Higher-Order Component, HOC) React (контейнерная компонента)

A

это один из продвинутых способов для повторного использования логики.

Это функция, которая на вход принимает одну компоненту, и выкидывает эту же компоненту, но обернутую в какую-то контейнерную компоненту.

Это нужно, чтобы переиспользовать логику и не дублировать код. В контейнерной компоненте сидит логика, и эту логику могут переиспользовать компоненты множество раз(компоненты, которые принимает та функция на вход)

С1 => function()=> C0(C1)(обернулась)

С2 => function()=> C0(C2)(обернулась)

С3 => function()=> C0(C3)(обернулась)

Примером может являться React.memo().
Она работает по принципу кеша - мы загрузили один раз с сервера картинку\аудио и он эту загрузку кеширует(сохраняет), чтобы снова использовать ее и не загружать с сервера повторно .

Как происходит с React.memo() - мы знаем, что при изменении компоненты, Реакт ее перерисовывает.
Если в компоненте находятся локальные стейты разных дочерних компонент, и один из этих локальных стейтов поменялся, то компонента перерисуется, перерисует дочернюю компоненту, стейт которого изменился + перерисует другую дочернюю компоненту, стейт которой НЕ менялся, те создатся новый виртуальный дом точно повторяющий старый виртуальный дом. И смысла в этом нет, плюс влияет на оптимизацию-долгая загрузка. Для этого есть вспомогательная функция высшего порядка (HOC), которая будет отслеживать приходят ли в компоненту новые данные-пропсы, которые изменят компоненту.
Для этого мы обворачивает компоненту, которая может перерисоваться без изменения стейта, в React.memo(UserSecret).

const UserSecret = ()=>{alert(‘Hi”)} -наша компонента

const User = React.memo(UserSecret) - обернули нашу компоненту UserSecret, создав новую - User.

Вызов компоненты происходит точно так же: <User></User>

В React.memo нужно оборачивать компоненты в 99% случаев.

Примечание: например, у дочерней компоненты вынесен в родительский компонент функция-коллбэк, например коллбэк OnClick-а вынесли в родит. компонент, то даже обернув дочернюю компоненту в useMemo, при изменении стейта в родит. компоненте, соответственно при перерисовки, дочерняя компонента все равно перересуется. Почему? Потому что при перерисовки коллбэк так же перерисуется и будет считаться за новую функцию. А эта новая функция пойдет через пропсы в дочернюю и будет считаться за обновленные данные, которые позволяют компоненте дочерней отрисоваться.
Решение - завернем коллбэк в useMemo:

const addBook = ()=>{…….} - наш коллбэк

const memoCallback = useMemo(()=>{ return addBook}, [book]) - завернули в useMemo и поставили зависимость, что если book поменяется, то выполнится эта функция. И эту функцию передаем теперь в пропсы в дочернюю компоненту.

Или есть такой вариант с useCallback: говорит, просто запомни эту функцию и возвращай всегда один и тот же коллбэк, пока не изменятся зависимости:
const memoCallback = useCallback(()=>{
// код коллбэка
}, [book])

https://github.com/ValeriyDyachenko/bxnotes/blob/master/content/lib/react/react-notes/rendering.md

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

Что такое React?

A

Реакт - библиотека т.к нужно доустанавливать Роутинг, Редакс и т.д по выбору.
Библиотеки React и React DOM предоставляют нам средства для создания UI. Мы сами их устанавливаем, используем только то, что нам нужно , контролируем их использование.

Angular - фреймворк, т.к дополнительно устанавливать ничего не требуется.
Внутри уже все есть нужное для работы и построения приложения

Грубо говоря библиотека это набор готовых решений, которые можно просто брать и использовать как захочется.
Фреймворк же накладывает опреденный стиль программирования, его элементы сильнее связаны между собой.

Точка входа - index.tsx. Там происходит render (root.render(<App></App>);) - сравнение двух виртуальных домов - старого и нового (что поменялось между ними).
render - это НЕ ОТРИСОВКА!!!!Как многие ошибочно думают. Вывод: render сначала сравнит 2 виртуальных дома, а затем перерисует изменения там, где они произошли.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

Для чего нужен Реакт?

A

React нужен для эффективной отрисовки страницы приложения, для этого у него есть Виртуальный DOM. Виртуальный ДОМ сравнивается с ДОМом Браузера, если есть различия –заменяется. Перерисовка происходит не всей страницы, а конкретного узла, в котором найдены различия.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

Как VDOM используется в Реакте?

A

В React каждая часть UI является компонентом и почти каждый компонент имеет состояние (state). При изменении состояния компонента, React обновляет VDOM. После обновления VDOM, React сравнивает его текущую версию с предыдущей(сравнивает старый Вирт.дом с новым)и ищет то, что поменялось. Этот процесс называется «поиском различий» (diffing).

После обнаружения объектов, изменившихся в VDOM, React обновляет соответствующие объекты в RDOM. Это существенно повышает производительность по сравнению с прямыми манипуляциями DOM. Именно это делает React высокопроизводительной библиотекой JavaScript.

https://habr.com/ru/companies/macloud/articles/558682/

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

Какой парадигме следует Реакт?

A

Реакт следует функциональной парадигме программирования.
Она базируется на чистых функциях - она не должна иметь побочных эффектов, она не должна изменять приходящие в нее данные, она может делать копию этих данных и уже можно модифицировать эту копию. Это называется Иммутабельность. Чистые функции всегда возвращают значение или другую функцию, а также не имеющие побочных эффектов.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

Что такое чистые функции?

A

Функция - это объект, т.к имеет свои встроенные свойства: name, constructor и тд.
Чистая функция не имеет бизнес-логики, не работает с ДОМ, не посылает запросы на сервер (сайд эффект), просто получает данные(пропсы) и отображает их.
Side Effect - запрос на сервер, работа с DOM, изменение параметров функции.

Принципы чистой функции:
1. Иммутабельность - функция не -имеет права изменить данные, которые в нее пришли. Делаем копию данных.
2. Идемпотентность - возвращает один и тот же результат, когда она вызывается с тем же набором аргументов. Результат функции предсказуем.
3. Имеет return, чтобы что-то возвращать.
4. Никаких side effects. Изменение значений в глобальном мире, асинхронные запросы.

Чистая функция требуется к компонентам, редьюсерам и селекторам.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

Что такое Принцип DRY?
5 принципов читаемого кода: KISS, YAGNI, DRY, BDUF и Бритва Оккама

A

DRY — Don’t Repeat Yourself (Не повторяйся).
React базируется на этом принципе - переиспользование компоненты, те UI необходимо создавать из переиспользуемых блоков.
Например, Создаем кнопку и подключаем ее, где и сколько раз необходимо. В плане логики здесь конечно также на помощь приходят вспомогательные функции (утилиты или хелперы) и хуки.
В целом,этот принцип говорит нам: -Избегать копирования кода
-Выносите общую логику
-Прежде чем добавлять функционал, проверить в проекте, может, он уже создан.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

Что означает SOLID?

A

Принципы о том, чтобы сделать модули менее связанными друг с другом и обособленными.

Single responsibility - принцип единственной ответственности.
Одна сущность отвечает(инкапсулирует) за одну задачу. Можно сказать, что это декомпозиция.
Что решает?
-Когда одна сущность разрастается и отвечает за множество задач(антипаттерн GodObject), мы получаем много связанного кода, что-то ломается одно - ломается другое. С Декомпозицией вносить изменения стало проще.
-Ухудшается читаемость

Open-closed — принцип открытости / закрытости.
Расширение функционала должно происходить за счет написания новых классов/компонент(
т.е. если мы хотим расширить(дополнить) каким либо дополнением(
например, у браузера есть доп.расширения, которые можно установить, у VSCode доустановим какие-то плагины)), а не догрузки старых классов/компонент(т.е. мы не изменяем старый код у VSCode или браузера, а допрописываем новый код для расширения).
Итог: открыт для расширения, закрыт для модификации
К этому относится и один из принципов ООП - наследование. Т.е. мы создаем новый экземпляр уже существующего класса с какими-то характеристиками. Тем самым мы не дублируем код.

L - принцип подстановки Барбары Лисков
Наследуемый класс должен дополнять, а не замещать поведение базового класса.
Например, у базового есть определенные методы, затем создаем наследуемые классы, один из которых решил изменить один из методов базового класса. Это не то, что нужно. В таком случае лучше создать базовый без этого метода, и создать наследуемые классы, в одном из которых будет этот метод, чтобы потом от этого класса создать еще наследуемые классы, содержащие этот метод.

I - принцип разделения интерфейсов.
Пример:
Например, мы создали интерфейс Payments, который содержит в себе несколько методов payWebMoney();
payCreditCard();
payPhoneNumber();
Далее нам надо реализовать два класса-сервиса, которые будут у себя реализовывать различные виды проведения оплат (класс InternetPaymentService и TerminalPaymentService).
При этом TerminalPaymentService не будет поддерживать проведение оплат по номеру телефона. Но если мы оба класса имплементим от интерфейса Payments, то мы будем “заставлять” TerminalPaymentService реализовывать метод, который ему не нужен.
public class InternetPaymentService implements Payments{ //базовый
public void payWebMoney() {
//logic
}
public void payCreditCard() {
//logic
}
public void payPhoneNumber() {
//logic
}
}
public class TerminalPaymentService implements Payments{
public void payWebMoney() {
//logic
}
public void payCreditCard() {
//logic
}
public void payPhoneNumber() {
//??????? этот метод здесь не нужен!!
}
}
Таким образом произойдет нарушение принципа разделения интерфейсов.

Для того чтобы этого не происходило необходимо разделить наш исходный интерфейс Payments на несколько и, создавая классы, имплементить в них только те интерфейсы с методами, которые им нужны.
public interface WebMoneyPayment {
void payWebMoney();
}
public interface CreditCardPayment {
void payCreditCard();
}
public interface PhoneNumberPayment {
void payPhoneNumber();
} //разделили на три интерфейса вместо одного

public class InternetPaymentService implements WebMoneyPayment, CreditCardPayment, PhoneNumberPayment{
//взяли все то, что нужно этому классу!!
public void payWebMoney() {
//logic
}
public void payCreditCard() {
//logic
}
public void payPhoneNumber() {
//logic
}
}
public class TerminalPaymentService implements WebMoneyPayment, CreditCardPayment{
//взяли все то, что нужно этому классу!!
public void payWebMoney() {
//logic
}
public void payCreditCard() {
//logic
}
}
Что решает?
-код становится менее связанным
-получаем более предсказуемую работу
-избавляем программные сущности от неиспользуемых методов

D - принцип инверсии зависимости.
Модули верхнего уровня не должны зависеть от модулей нижнего уровня.
Пример:
это просто небольшой магазин, где оплата происходит только за наличные.
Создаем класс Cash и класс Shop.
public class Cash {
public void doTransaction(BigDecimal amount){
//logic
}
}
public class Shop {
private Cash cash;
public Shop(Cash cash) {
this.cash = cash;
}
public void doPayment(Object order, BigDecimal amount){
cash.doTransaction(amount);
}
}
мы уже нарушили принцип инверсии зависимостей, так как мы тесно связали оплату наличными к нашему магазину.
И если в дальнейшем нам необходимо будет добавить оплату еще банковской картой и телефоном (“100% понадобится”), то нам придется переписывать и изменять много кода. Мы в нашем коде модуль верхнего уровня тесно связали с модулем нижнего уровня, а нужно чтобы оба уровня зависели от абстракции.

Поэтому создадим интерфейс Payments.
public interface Payments {
void doTransaction(BigDecimal amount);
}
Теперь все наши классы по оплате будут имплементить данный интерфейс.
public class Cash implements Payments{
public void doTransaction(BigDecimal amount) {
//logic
}
}
public class BankCard implements Payments{
public void doTransaction(BigDecimal amount) {
//logic
}
}
public class PayByPhone implements Payments {
public void doTransaction(BigDecimal amount) {
//logic
}
}
Теперь надо перепроектировать реализацию нашего магазина.
public class Shop {
private Payments payments;

public Shop(Payments payments) {
    this.payments = payments;
}

public void doPayment(Object order, BigDecimal amount){
    payments.doTransaction(amount); //выбрали способ картой
} } Сейчас наш магазин слабо связан с системой оплаты, то есть он зависит от абстракции и уже не важно каким способом оплаты будут пользоваться (наличными, картой или телефоном) все будет работать.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

Назовите хотя бы 2 диапазона HTTP статусов и что они означают?

A

Делаем запрос на сервер (request) , сервер возвращает ответ(объект-response). И в нем могут находится разные статусы:
200 - OK
300 - перемещение (301 - перенаправляет на новый сайт, он не работает, 302 - тех.работы, временное перемещение)
400 - ошибка клиента (404 - не найдено, данные неверны)
5xx - ошибка сервера.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

Соотнесите типы HTTP-запросов с CRUD(create, read, update, delete) операциями.

A

Если мы хотим прочитать данные(R-read), то отправляем GET-запрос.

Добавить новые данные(С-create)- POST.

Изменить данные(U-update) - PUT.
В дополнение: чем отличается PUT от PATCH - если мы обновляем с помощью put, то мы отправляем на сервер ВСЮ сущность, даже если нам надо обновить одно свойство. patch - отправляем только то\те, свойства , которые хотим обновить, БЕЗ всей сущности.

Удалить данные(D-delete)- DELETE.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

Что такое Reducer?

A

Это чистая функция, которая принимает стейт и action. Action - объект, т.е. как инструкция, которая говорит как именно пришедший стейт обработать\изменить. В нем обязательно содержится тип type и другие необходимые данные. По типу action-на ищется тот кейс, который необходимо выполнить для стейта

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

Для чего нужен импорт Реакта в файле jsx?

A

Компонента, которая содержит jsx-разметку будет ругаться без импорта Реакта. jsx считается расширением js. jsx не попадает в браузер, тк он его не понимает. он превращается благодаря траспилятору babel в js. При этом нам понадобится импорт Реакта

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

Что такое useMemo()
Что такое React.memo()

A

У функциональных компонентов есть проблема - весь код в теле выполняется при каждом обновлении.

useMemo - это хук, который сохраняет результат вызова функции (первый аргумент) и пересчитывает его только при изменении зависимостей (второй аргумент). useMemo возвращает результат вызова первого аргумента.

const result = useMemo(() => sum(num), [num]);

Он будет сравнивать поменялся ли num, если да, то вызовется первый параметр - sum(num) с новым num.

В useMemo мы оборачиваем только сложный код, который требует большого времени обработки, например, там есть глубокая вложенность.
Так же мы можем обернуть в useMemo и разметку, но если этого требуется, если, например, там вызываются сложные компоненты.

React.memo() компонент более высокого порядка. Он принимает компонент в качестве аргумента и запоминает результат. Мемоизированный результат обновляется только в случае изменения свойств исходного компонента.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

Что такое TDD?

A

Test-driven development или процесс разработки через тестирование — это методология разработки программного обеспечения, которая основывается на повторении коротких циклов разработки: изначально пишется тест, покрывающий желаемое изменение, затем пишется программный код, который реализует желаемое поведение системы и позволит пройти написанный тест, а затем проводится рефакторинг написанного кода с постоянной проверкой прохождения всех тестов.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

Чем отличаются SQL от noSQL базы данных?

A

SQL база данных - язык запросов, созданный для того, чтобы получать из базы данных необходимую информацию.
Схему работы SQL:
специалист формирует запрос и направляет его в базу. Та в свою очередь обрабатывает эту информацию, «понимает», что именно нужно специалисту, и отправляет ответ.

Данные хранятся в виде таблиц, они структурированы и разложены по строкам и столбцам, чтобы ими легче было оперировать. Такой способ хранения информации называют реляционными базами данных (от англ. relation — «отношения»). Название указывает на то, что объекты в такой базе связаны определенными отношениями.
Пример, MySQL

noSQL — это семейство нереляционных баз данных. В них разработчики отошли от использования традиционной табличной модели представления информации.

Нет единого стандарта: у каждой такой базы индивидуальный подход к записи, хранению и извлечению данных. Поиск информации может вестись, например, по парам «ключ — значение» или по наборам столбцов.

Пример, MongoBD. Она использует JSON-подобные документы с динамическими схемами, что облегчает хранение и запрос данных.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
17
Q

Что такое nodejs?

A

Браузер содержит движок v8, который может выполнять js. Со временем люди поняли, что js можно использовать не только для отображения UI в браузере, а еще и для того, чтобы делать запросы в БД, файловую систему(file system) и тд.
Движок v8 не может это все одновременно выполнять(single responsibility), его задача - парсить js и выполнять базовые функции, который он может делать, по этому решили создать альтернативную браузеру программу\платформу - Nodejs. Он так же использует движок v8, чтобы уметь понимать js.

Помимо того, что браузер содержит v8, который с js, он еще и привносит свои фишки - DOM, работа со стилями, ассинхронность - запросы на сервер с помощью fetch.

Итого, Nodejs - программа\платформа, построенная на движке v8, который может выполнять js. Для чего он нужен? С помощью написанных расширений, пакетов, он может работать с БД, с файловой системой, с сетевыми протоколами, можно построить сервис на нем

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
18
Q

Нужен ли import React , когда мы пишем компоненту?

A

Так как браузеры не понимают JSX “из коробки”, разработчики полагаются на компиляторы типа Babel или Typescript, чтобы трансформировать JSX в обычный JS.
В React 17 Release Candidate появился новый, опциональный механизм трасформации JSX в JS.
Старая JSX трасформация работала следующим образом:

import React from ‘react’;
// обязательно с импортом Реакт

function App() {
return <h1>Hello World</h1>;
}

Трасформировался в:

import React from ‘react’;

function App() {
return React.createElement(‘h1’, null, ‘Hello world’);
}

Чтобы это решить в React 17 появляются две новые точки входа предназначенные для использования другими инструментами такими как Babel и Typescript и теперь вместо трансформации в React.createElement, импортируются и вызываются новые функции из пакета React.

Предположим ваш код выглядел вот так:
function App() { //теперь можно без импорта
return <h1>Hello World</h1>;
}

После новой трансформации он будет выглядеть вот так:
// Inserted by a compiler (don’t import it yourself!)
import {jsx as _jsx} from ‘react/jsx-runtime’;

function App() {
return _jsx(‘h1’, { children: ‘Hello world’ });
}

Новый механизм не импортирует React, хотя он всё ещё нужен для работы хуков.!!!

Как убрать неиспользуемые импорты React:

cd your_project
npx react-codemod update-react-imports

В результате:
-Удалятся все неиспользуемые импорты React
-Изменятся все импорты типа import React from «react» на именованные import { useState } from «react». Это предпочтительный способ импорта. Codemod не затронет импорты типа import * as React from «react», это тоже валидный импорт и в 17 версии он будет работать, но в дальнейшем мы будем просить избавляться от него

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
19
Q

Что такое Babel в Реакте?

A

Babel — это компилятор, который преобразует ваш современный JavaScript для запуска в старых браузерах. Он также может выполнять и другие задачи, такие как преобразование синтаксиса JSX.

Это специальный скрипт, который позволяет при запуске веб-страницы в браузере на лету преобразовать весь содержащийся на ней код React в код javascript, понятный браузеру.

Babel преобразовывает JSX в js на этапе сборки-компиляции. Реакт на основе js должен создать Виртуальный Дом с объектами-узлами, после чего Реакт превратит эти объекты в объекты Реального Дома.
Из JSX в js - теги превращаются в document.createElement(…..).
Но уже этой функции нет, почему и можно не использовать Импорт Реакт, тк при компиляции с Babel, Babel делает импорт этой функции за нас.

Наш код:
function App() {
return <h1>Hello World</h1>;
}
Транспиляция по-новой:
import {jsx as _jsx} from ‘react/jsx-runtime’;
// импортнул за нас

function App() {
return _jsx(‘h1’, { children: ‘Hello world’ });
}

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
20
Q

Что такое one-way binding и two-way binding?

A

Есть однонаправленный поток данных (one-way). Это означает, что одна часть кода может передавать в другую часть кода данные, а другая часть может получать и этот поток никак не меняется. В таком потоке данные «текут» от одного модуля к другому, а выходные данные предыдущего становятся входными следующего. Получается круговорот.
Яркий пример такой архитектуры потока - Редакс.
Например, пользователь нажимает кнопку-Представлении(UI) вызывает action, в котором содержится инфа что произошло. Action попадает в Диспатч и распространяет его по всем Редьюсерам, которые знают как его обработать. Редьюсеры преобразовывают данные в хранилище, тем самым это обновление данных влечет перерисовку Представления и цикл замыкается

Двунаправленный поток данных(two-way):
Данные в таком потоке могут передаваться в обе стороны.
Например, используется для связывания хранилища и представления, чтобы обновление, например, текста в поле ввода сразу обновило данные в хранилище.
Из плюсов:
Меньше кода, потому что не надо писать экшен и обработчик для него.
Из минусов:
Труднее отлаживать, когда двойное связывание используется для чего-то сложнее, чем обновление текста в поле ввода.
Фреймворки, например Вью И Ангуляр, которые используют двунаправленное связывание, часто реактивные — то есть применяют изменения мгновенно не только к UI, но и к вычисляемым данным.
Пример в Ангуляре - двустороннее связывание,

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
21
Q

Является ли Реакт реактивным?

A

https://dev.to/balaevarif/pochiemu-react-nie-rieaktivien-40ig

В реактивном программировании при возникновении какого-либо события, например, клик на кнопку, или ответы из бэкенда, кэш, структуры данных, все это может быть представлено в виде ассинхронных потоков.
Поток - это последовательность событий, разворачивающихся во времени. Т.е. они идут друг за другом в зависимости раньше они появились другого или позже.
На эти потоки можно подписаться и реагировать на изменения.
Тот, кто создает событие, называется observer, а тот, кто получает (слушает) и обрабатывает его - subscriber.
Т.е. подписанные на поток subscriber-ы как-то обрабатывают его, когда событие возникло.
Реактивное программирование подразумевает реакцию на потоки событий, а не явный запрос какого-то действия от пользователя.

Что касается Реакта:
КАК React обрабатывает события и изменяет UI?
Если мы будем вызывать множество изменений state друг за другом, то React будет стараться их объединить и произвести меньше UI (DOM) изменений.
Всё это сделано, чтобы оптимизировать изменения DOM элементов.
React “планирует” изменения UI. Они могут быть не равны количеству поступающих событий.

Отсюда теряется понятие потоковости и “реактивности”. Это очень хорошо заметно, если попробовать реализовать с помощью React приложение, основанное на системе постоянных событий (например, реальновременной графики), которые “пушатся” извне.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
22
Q

Что происходит на Реакте, когда пользователь что-то сделал на UI, например кликнул по кнопке?

A

Процесс обновления UI в React приложении состоит из трех фаз: (что-то произошло на UI)

1.Render — формирование текущего дерева компонентов на основании их свойств (props) и состояния (state).
Render не перерисовывает DOM дерево, его задача — формирование “виртуального” дерева.

2.Reconciliation(Согласование) — сравнение и вычисление отличий с предыдущим деревом.
Если полученное дерево совпадает с предыдущим, то обновления DOM не произойдет.

3.Commit — обновление DOM

  1. Render:
    Срабатывает событие-коллбэк, который приведет к изменению стейта(useState, useReducer)(или например изменение приходящих пропсов), происходит ре-рендер компоненты-функция перевызывается. Если в ней сидят дочерние компоненты, они тоже будут перевызываться. Далее работает Babel-транспилирует jsx код в js. Теперь появляется Новый Виртуальный Дом.

2.Reconciliation:
Новый Виртуальный Дом сравнивается со старым Виртуальным Домом, сравниваются объекты(узлы ДОМ-а) старого ВД и нового ВД, где появились\заменились на новые объекты-узлы.

3.Commit:
Внесение этих изменений в Реальный Дом.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
23
Q

Как происходит первичный рендеринг?

A

Render — формирование текущего дерева компонентов на основании их свойств (props) и состояния (state).

При первом запуске приложения, в index.js необходимо вызвать рендеринг с помощью вызова createRoot(document.getElementById(‘root’)) c полученным корневым Дом-элементом-узлом из index.html.
Затем происходит первичный рендер-вызов корневой компоненты -
т.е. вызываем методом .root(<App></App>)
Таким образом происходит вызов корневой компоненты и каскадом ниспадает на остальные компоненты, получая от всех jsx-разметку, затем с помощью Babel транспилируется в js(раньше было с помощью React.createElement), с помощью которого Реакт создает Виртуальный Дом

Рендерится корневая компонента, подтягивая дочерние. Они возвращают jsx-разметку, Babel транспилирует в js, формируется Виртуальный Дом.
Затем происходит отрисовка в браузере.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
24
Q

Если у нас функция вне компоненты возвращает какие-то тяжелые большие вычисления, вызываем ее в нашей компоненте и эти вычисления мы используем в качестве инициализационного значения в useState, то как избежать того, чтобы при изменении стейта функция эта не перевызывалась каждый раз? Ведь будут происходить тяжелые вычисления каждый раз, что повлияет на оптимизацию.

A

Можно вызов этой функции завернуть в useMemo и сделать зависимость пустой, чтобы она вызывалась только один раз.

function hardDate(){ // функция с тяжелыми выч.
……
return 34488365536536
}

function State(){ // наша компонента

const initialValue = useMemo(hardDate, [])
// завернули в useMemo, вызов один раз

const [counter, setCounter] = useState(initialValue )
//попавшее сюда первый раз инициализационное значение так и будет сидеть, несмотря на то, что функция могла бы каждый раз перезапускаться без useMemo.
// каждый раз это число будет увеличиваться на 1, функция уже не будет перезапускаться.

return
<>
<button onClick={()=>setCounter(counter+1)}>INC</button>
</>
}

Но useState сам может оптимизировать:
вместо инициализационного значения из переменной, передадим функцию ему и он возьмет в качестве инициализационного значения то, что она вернет:

const [counter, setCounter] = useState(hardDate)

useState вызовет эту функцию ОДИН раз и возьмет ее значение. Например, если мы вдруг захотим взять counter, который якобы хранит эту функцию, то не получится, т.к. он ее не хранит, а просто вызывает и забирает значение.

так же setCounter может принимать не только какое-то значение, а функцию, которая по каким-то правилам будет изменять стейт.

const inc = (state: number)=>{
return state+1
}

return
<>
<button onClick={()=>setCounter(inc )}>INC</button>
</>

// укороченный вариант
<button onClick={()=>setCounter((state: number)=> return state+1)}>INC</button>

Т.е. мы можем использовать функцию в setCounter , когда нужно обновить состояние основываясь на текущих данных, которые в данный момент находятся в состоянии.
Это функция, которая принимает предыдущее состояние и возвращает новое состояние

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
25
Q

Что такое useEffect?

A

Это Хук для работы с сайд эффектами такими как запрос на сервер, setTimeout, getElementById, document.title.
Важно запомнить - сначала происходит отрисовка контента, потом запускается коллбэк в useEffect, т.е. первая отрисовка - функция-компонента вызывается , например, инициализируется переменная, фиксируется useEffect, но он не запускается, оставляет на потом, Реакт получает от компоненты jsx, отрисовывает, а потом после всего этого запускает коллбэк useEffect-а.
Вывод: сначала должно что-то отобразиться в Представлении, а потом уже запускается коллбэк.

Например, при повторном рендеренге - нажимаем на кнопку, чтобы увеличить счетчик,стейт изменился, перевызвалась функция, увеличенный счетчик отобразиться в Представлении, а уже только потом запустится коллбэк useEffect.

Зависимости:
[] - будет запущен при первичном рендеренге
[counter] - будет перезапускаться каждый раз при изменения стейта - counter
нет зависимости - будет запускаться каждый раз при ре-рендеринга компоненты

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
26
Q

Что такое clean up в useEffect?

A

Помним, что useEffect будет вызван только тогда, когда будет отрисован контент(оч кратко: Реакт возьмет jsx, создаст Вирт.Дом, затем Реал.Дом).

После useEffect может образовывать множество мусора в виде setTimout, задержанного ответа от сервера, подписка на какой-то ДОМ-элемент и тд. тогда, когда компонента уже будет размонтирована(например, произойдет ре-рендер компоненты). По этому внутри коллбэка в конце ставится функция clean up
Пример:
return ()=> clearInterval(id).

При пустой зависимости [], когда useEffect запускается один раз при рендере компоненты, то побочные сайды очищаются при демонтировании компоненты.
Когда есть зависимость [counter], то useEffect запускается когда меняется стейт, тем самым происходит ререндер компоненты, эта самая очистка очищает то, что было ДО ререндера компоненты, т.е. если у нас в локальном стейте сидел 0 и он увеличился на 1, то очистка будет происходить с нулем, с данными, которые были ДО ререндера.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
27
Q

Зачем нужна функция React.createContext и примеры ее использования?

A

React Context - способ управления состоянием, заменив Redux.

Вообще Контекст разработан для передачи данных, которые можно назвать «глобальными» для всего дерева React-компонентов .

Этот объект Context создается с помощью React.createContext отдельно:
const MyContext = React.createContext({} as StoreType)

Дальше какая-то из компонент может быть Провайдером этого контекста и положить props - данные, например, стор:
<MyContext.Provider store={props.store}>

Далее этот пропс-стор позволяет использовать дочерние компоненты-потребители-сonsumer-ы Провайдера.

<MyContext.Consumer>
{value => /* отрендерить что-то, используя значение контекста */}
</MyContext.Consumer>

Все потребители, которые являются потомками Provider, будут повторно рендериться, как только проп value у Provider изменится.

То есть не нужно теперь передавать по дереву иерархии передавать через пропсы там, где не нужно.

Итог: контекст нужен для того, чтобы пробрасывать дочерним компонентам что-то глобальное\общее, что нужно всем компонентам - тема, язык, настройки, хранилище-стейт, роутинг

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
28
Q

Что такое условный рендеринг и первичный\начальный\инициализационный рендеринг?

A

Условный рендеринг - можно условно выводить JSX, используя синтаксис JavaScript, такой как операторы if, && и ? :.

Первичный рендеринг:
Когда приложение запускается, нам необходимо вызвать начальный рендеринг.
Он выполняется вызовом createRoot с корневым узлом DOM, а затем вызовом его метода render с нашим компонентом:
const root = createRoot(document.getElementById(‘root’));
root.render(<App></App>);

После запуска рендеринга React вызывает наши компоненты, чтобы определить, что отобразить на экране. “Рендеринг” - это обращение React к вашим компонентам. При первом рендере React вызывает корневой компонент - App.
И спускается каскадом вниз по компонентам, они возвращают jsx разметку, которую Babel транспилирует в js, затем на основе этого js, React создаст DOM-узлы для тегов <section>, <h1> и трех <img></img>(пример всех тегов из всех компонент) которые будут находится в Реальном Доме.
Затем происходит браузерный рендеринг - браузер отрисовывает экран.

https://www.youtube.com/watch?v=rsW9_UtF4jk
// Virtual DOM

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
29
Q

Что такое батчинг?

A

Батчингом в React называют процесс группировки нескольких вызовов обновления состояния в один этап ререндера.
Это положительно сказывается на производительности.
Т.е. Реакт ждет, ждет, пока не будет выполнен весь код в обработчиках событий, прежде чем обрабатывать ваши обновления состояния.
Только после выполнения будет происходить ОДИН ре-рендер, а не три.

<button
onClick={() => {
setNumber(number + 1);
setNumber2(number + 3);
setNumber3(number + 4);
}}
>
+3
</button>

Так же Реакт добавил возможность обновления состояний для асинхронных операций: promise, таймауты, fetch запросы:
setTimeout(() => {
setCount(c => c + 1);
setFlag(f => !f);
// React будет вызывать ререндер только один раз, в конце
}, 1000);

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
30
Q

Что отличает Flux от Redux?

A

Основные отличия между Flux и Redux заключаются в том, что Flux – это архитектурный шаблон, в то время как Redux – это библиотека, которая строится на идеях Flux.
Redux также добавляет новые возможности и использует иммутабельные объекты для управления состоянием.

Flux – архитектурный шаблон, разработанный в Facebook, который описывает, как управлять состоянием приложения.
Он состоит из четырех компонентов: View-Компонента, Action, Dispatcher-контроллер, который отвечает за обработку входящих экшенов, и Store-Хранилище. Причем этих сторов может быть несколько.
Основной идеей Flux является однонаправленный поток данных, где данные изменяются только через Action и могут быть получены View только от Store.

Redux – библиотека, которая упрощает работу с управлением состояния. Она использует идеи Flux, но добавляет новые возможности …
В Redux так же используется однонаправленный поток данных, но имеет отличие от Flux-архитектуры потоков данных. Так же у Редакс может быть только один стор.
Еще основное отличие - использование иммутабельных объектов. Значения состояния(стор) не могут быть изменены напрямую, они могут быть изменены только путем создания нового объекта. {…store}.

И еще одна отличие в архитектуре потоков данных:

Flux имеет строго определенную однонаправленную структуру данных, которая включает в себя хранилище состояний (store), действия (actions) и диспетчер (dispatcher). Каждое action-действие отправляется через dispatcher-диспетчер, который распределяет его на соответствующий метод В store.

Redux, с другой стороны, использует паттерн Redux cycle, который состоит из трех основных элементов: действия (actions), редюсеры (reducers) и хранилище (store).

Еще отличие:
Во Flux изменение состояния происходит путем создания действий и передачи их в хранилище, после чего они распределяются на все компоненты, которые подписались на эти изменения.

У Redux в отличие от Flux, изменение состояния происходит с помощью чистых функций-редюсеров. Когда действие передается в хранилище, оно передается в соответствующий редюсер, который изменяет состояние и возвращает новый объект с обновленными данными. Компоненты получают новое состояние через подписку на хранилище.(useSelect подписывается на стор)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
31
Q

В чем фишка наследоваться от Reac.PureComponent вместо React.Component?
(это extends в классовых компонентах). И привести аналогию с функциональными компонентами.

A

React.Component — это базовый класс для компонентов React, объявленных как ES6-классы:
class Greeting extends React.Component {
render() {
return <h1>Привет, {this.props.name}</h1>;
}
}
React.PureComponent похож на React.Component. Отличие заключается в том, что React.Component не реализует жизненный метод цикла - shouldComponentUpdate()(означает: следует ли мне обновить компоненту? будет либо true, либо false),
а в React.PureComponent уже реализован этот метода. То есть сам Реакт дергает компоненту, справшивая, при таких приходящих пропсах и при твоем локальном стейте(а у классовых есть свой локал.стейт) будешь ли ты возвращать новый jsx или нет смысла, тк состояние и пропсы не поменялись? При этом делается поверхностное сравнение
Если он скажет false, то Реакт не будет дальше брать jsx, транспилировать и далее обновлять Представление уже по длиной цепочке.

Все это по аналогии в функциональных компоненах - т.е. мы используем HOC(функция высшего порядка) React.memo(()=>{наша функция}) для того, чтобы не дергались дочерние компоненты, если в ее родительской произошло изменение стейт, например. Происходит МЕМОИЗАЦИЯ, React будет использовать последнюю отрисованную версию этого компонента-кеширование.
Произойдет ре-рендер только если изменился стейт, который связан с этой компонентой, либо изменились приходящие пропсы.

React.memo - HOC
useMemo - хук

32
Q

Перечислите методы жизненного цикла в правильном порядке.

A

Методы жизненного цикла дают возможность запускать код в конкретные моменты жизни компонента либо в ответ на какие-нибудь изменения.

По сути выделяют 4 этапа жизненного цикла:
инициализация, Initialization
монтирование, Mounting
обновление Updation
и размонтирование Unmouting

Инициализация:

Это фаза, на которой компонент собирается начать свой путь, установив состояние и пропсы. Обычно это делается внутри метода конструктора:
Сonstructor:
class Initial extends React.Component{
constructor(props){
super(props)
this.state={ // инициализация
date: new Date()
}
}
}

Монтирование:

Это фаза, на которой наш компонент React монтируется в DOM (то есть создается и вставляется в DOM). На этом этапе наш компонент рендерится в первый раз.

1.componentWillMount():
Этот метод вызывается непосредственно ПЕРЕД монтированием компонента в DOM или методом визуализации. Вызывается перед методом render. После этого метода компонент монтируется.

Промежуток: здесь происходит .render() компоненты.

  1. componentDidMount()
    Этот метод вызывается ПОСЛЕ монтирования компонента в DOM. Как и componentWillMount, он вызывается один раз в жизненном цикле. Перед выполнением этого метода вызывается метод .render (т.е. Мы можем получить доступ к DOM).

Обновление:

Это то место где состояние компонента изменяется и, следовательно, происходит повторный рендеринг. На этом этапе данные компонента (state и props) обновляются в ответ на пользовательские события.

  1. shouldComponentUpdate()
    Этот метод определяет, должен ли компонент обновляться или нет. По умолчанию возвращает true.
    shouldComponentUpdate(nextProps, nextProps)
    // хотим, чтобы произошел ре-рендер компоненты только после того, если изменились пропсы или стейт. Он получает такие аргументы, как nextProps и nextState, которые помогают нам решить, следует ли выполнить повторную визуализацию, выполнив сравнение с текущим значением prop.
    nextProps - это следующее значение props, которое получит компонент
    nextState- это следующее значение state, которое получит компонент
    Пример:
    shouldComponentUpdate(nextProps, nextState) {
    if (this.state.count === nextState.count) {
    return false
    //сравниваем, если стейт не понялся, то ре-рендеринга не будет
    }
    return true
    //если поменялся, то ре-рендер компоненты будет
    }
  2. componentWillUpdate ()
    Он вызывается до повторного рендеринга компонента. Он вызывается один раз после метода shouldComponentUpdate .

Промежуток: здесь происходит render()

  1. componentDidUpdate()
    Этот метод вызывается сразу после повторного рендеринга компонента. После того, как компонент обновляется в DOM.

Размонтирование:

Это последний этап в жизненном цикле компонента. Компонент отключается от DOM на этом этапе.

  1. componentWillUnmount()
    Вызывается перед размонтированием компонента, перед удалением компонента из DOM.

https://dev-gang.ru/article/kak-ponjat-metody-zhiznennogo-cikla-komponenta-v-reactjs-m3v6725v7q/ - все здесь

33
Q

Что такое иммутабельность?

A

Иммутабельность предполагает, что после создания данные или структура, которая их содержит, не могут быть изменены.

Неизменяемым (англ. immutable) называется объект, состояние которого не может быть изменено после создания.
Результатом любой модификации такого объекта всегда будет новый объект, при этом старый объект не изменится.
Если объект имеет вложенность, то из нового объекта все вложенные объекты, которые не подверглись модификации, будут ссылаться на старые.

Метод Object.freeze замораживает объект. Он предотвращает добавление новых свойств к объекту, удаление старых свойств из объекта и изменение существующих свойств

Наапример, мы уже используем иммутабельные структуры данных: строки - Все методы в String.prototype предоставляют возможности либо только для чтения, либо возвращают новую строку.

34
Q

Что такое Redax?

A

Это библиотека, состоящая из объекта-store - хранилище.
Создавая это хранилище, мы создаем combineReducers, помещая в него наши Редьюсеры, из которых он будет состоять.
Редьюсеры - чистые функции, которые принимают на вход стейт и action(action-объект, который содержит как минимум type и может содержать доп.свойства) и преобразовывает иммутабельно стейт, возвращая его.

Со store - хранилищем можно взаимодействовать тремя методами(он их содержит):

store .getStore() - позволяет получить атктальный стейт из стора.

store .subscribe(subscriber) - позволяет subscriber-у подписаться на изменения стейта. subscriber - это всегда функция, которую вызовет стор, когда будет изменения в стор.

store.dispatch(action) - единственная возможность преобразовать стейт - задиспатчить из внешнего мира action. action - это как инструкция, которая говорит что делать со стейтом.(удалить\добавить и т.д.)
Кстати, диспатч action отправляет во все редьюсеры, он проходится по всем и задерживается там, где необходимо.

При запуске приложения со стороны Редакса происходит это - Редакс запускает все редьюсеры, чтобы организовать нам стейт из инициализационных значений(дефолтных\начальных)

35
Q

Для чего нужна библиотека React-Redax?

A

Это менеджер состояний.
Обеспечивает взаимодействие компоненты со стором.
Оборачивая компоненту, которая будет проводником стора, в
<Provider store={store}><App></App></Provider >
Этот Провайдер добавляет стор в Контекст с помощью Context API.
И любая дочерняя компонента может стать consumer-потребителем этого контекста и достать из этого Контекста то, что положил родитель.
Context API — это структура React, которая позволяет всем уровням приложения обмениваться конкретными данными и помогает решить проблему пробрасывания.
Контекст позволяет передавать данные через дерево компонентов без необходимости передавать пропсы на промежуточных уровнях.

36
Q

useSelector() для чего?

A

useSelector() позволяет извлекать данные из состояния(state) хранилища(store) Redux с помощью функции селектора.

const result: any = useSelector(selector: Function(например,()=> state=>state.todolists), equalityFn?: Function)

useSelector() будет ПОДПИСЫВАТЬСЯ на хранилище Redux и запускать наша функция selector всякий раз, когда отправляется(dispatch) действие.

После отправки(dispatch) действия, useSelector() выполнит сравнение по ссылке предыдущего значения результата селектора и текущего значения результата(функция selector возвращает полученный стейт в том виде, который мы зададим, например, state.todolists), если они разные, то перерендерит компоненту, если нет - нет

Так же

37
Q

Разница между useMemo и useCallback?

A

useMemo вызывает функцию при изменении зависимостей и memoizes (запоминает) результат функции между рендерами.
Используем, если хотим избежать повторного выполнения дорогостоящих вычислений для генерации нового значения.

useCallback запоминает существующее значение (обычно определение функции) между рендерами, т.е. запоминает САМУ функцию и ее вызов, а не результат этой функции.

«Мое приложение работает медленно и требует больших вычислений» - это проблема, которую помогает решить useMemo. Запусти приложение через React DevTools Profiler, а также через Google Lighthouse или WebPageTest, чтобы понять показатели производительности, оберни свои вычисления в useMemo, а затем измерь ещё раз.

Почему не нужно везде использовать useMemo для оптимизации?
При настройке useMemo возникают дополнительные затраты (например, использование памяти), которые могут очень быстро перевесить выигрыш в производительности от запоминания возможных значений каждой отдельной функции.

Можно полагаться на useMemo как на оптимизацию производительности, а не как
сохранение всех своих значений между рендерами, тк кеш не гарантирует сохранения всех этих значений.
Для версии useMemo со стабильным кешем смотри UseMemoOne.

38
Q

Что такое Storybook?

A

Это библиотека для разработки пользовательских интерфейсов.
Позволяет разрабатывать компоненты в отрыве от работы нашего приложения, не запуская его.
Создается документация наших компонент - можно посмотреть что создано, как они выглядят, использовать, переиспользовать.
Можем тестировать наши компоненты.
Можно внести интерактивность - например, вводить данные и смотреть как они отработают.

39
Q

Какие хуки заменяют методы жизненного цикла?

A
  1. componentWillMount() - Хук useLayoutEffect()
    Он запускает эффект перед отрисовкой компонента. Данный хук предназначен для запуска эффектов, влияющих на внешний вид DOM, незаметно для пользователя.
  2. componentDidMount()
    componentDidUpdate()
    componentWillUnmount()
    - Хук useEffect()
    Он для запуска побочных эффектов (например, выполнение сетевого запроса или добавление обработчика событий) после монтирования и отрисовки компонента.
    Отрабатывает после первой отрисовки компоненты(componentDidMount()) и каждого обновления компонента(componentDidUpdate()), например поменялся стейт.
    И для очистки эффекта - для этого достаточно вернуть функцию из useEffect(), внутри которой выполняется очистка:
    useEffect(() => {
    const id = setTimeout(/* какой-то код с userId */);

return () => clearTimeout(id);
}, [userId]);

Для имитации componentWillUnmount() достаточно соединить очистку с пустым массивом вторым параметром:
useEffect(() => {
return () => {
// Эта логика выполнится только при размонтировании компонента
};
}, []);
результат функции — это новая функция, которая вызывается только при размонтировании (componentWillUnmount)

40
Q

Что такое трехуровневая архитектура Реакта и Редакса?

A

Состоит из трех уровней -
UI(компоненты, Представление),
BLL(бизнес-логика, где хранится стейт всего приложения),
DAL(api, где происходит запрос на сервер).

Пример, пользователь решил удалить тудулист, нажал на кнопку=> диспатчим санку( dispatch(deleteUserTS(todolistId) ) с необходимыми параментрами, например, id тудулиста.
Это происходит на уровне UI.
Подключенный middleware проверяет на входе экшен это или санка, если экшен, то пропускает дальше в редьюсер, если санка, то вызывает эту функцию, засунув при этом диспатч и getState.
Далее в санке, которая находится на уровне BLL, вызываем api на уровне DAL, обращаясь к нему (todolistsAPI.deleteTodolist(todolistId)).
На этом уровне DAL происходит запрос и возврат пришедших данных.
Далее в этой же санке диспатчим в редьюсер и экшен(dispatch(removeTodolistAC(todolistId))), если результат пришедший с сервера успешен.
Редьюсер меняет стейт, возвращает. А в нужных компонентах берется обновленный стейт из useSelector(). И компонента обновится.

41
Q

У useSelector есть второй параметр, что он делает?

A

У него есть второй параметр-функция, которая проверяет изменялся ли стор с предыдущего рендера (сравнивает два значения - новое(обновленное) из стейта и старое из стейта). По результату, если есть изменения в значениях, то селектор заставляет компоненту ререндерится.
Может появится проблема лишнего рендера компоненты, когда мы делаем какие-то сложные вычисления, сортировку / фильтрацию, написав такой селектор, т.к. useSelector будет сравнивать старое и новое значения. Например, метод фильтрации возвращает новый массив, а значит, уже для селектора есть отличие.
Но! Если возвращается примитив(не массив, не объект, то useSelector не будет ререндерить компоненту)

Есть решение - использовать из библиотеки reselect функцию createSelector. Она будет кэшировать результаты вызова селекторов и предотвращая повторные вычисления

export const packsSelector = (state: RootState) => state.packs.cardPacks;
//не пишем useSelector

export const filteredByNamePacksSelector = createSelector(
// 1 - массив селекторов(может принимать несколько)
[packsSelector],
// 2 - функция, которая принимает данные от селекторов и возвращает новое значение
(packs) => {//массив карточек
console.log(“filteredByNamePacksSelector”);
return packs.filter((p) => p.name.includes(“f”));
}//отфильтровали карточки
);

В компоненте, где планируется использовать выведенный стейт, можем написать так:
const todolists = useSelector(filteredByNamePacksSelector или packsSelector);

Чтобы было проще с импортом всех этих селекторов, создаем новый файл index.ts в той же папке и прописываем так:
export * as counterSelectors from ‘./selectors’
Теперь можно в компоненте прописывать так:
const todolists = useSelector(counterSelectors.packsSelector)

В итоге есть два вида селекторов:
1. Обычный, где достаем нужный нам стейт.
Такие селекторы стоит использовать всегда, когда мы напрямую ссылаемся на данные из стора. Даже если возвращаемое значение является объектом, не стоит беспокоиться - мы лишь возвращаем ссылку на уже существующий объект, который находится в стейте.
(не обязательно) Можно использовать, когда нужно сделать простую операцию между какими-то значениями, при этом результатом этой операции является примитив.
2. Селектор, который мемоизирует свой прошлый результат - они проверяют входные данные функции, и если они не изменились - сразу же возвращают уже существующее значение, которое было рассчитано ранее.
В селекторе есть тяжелые вычисления (фильтрация, сортировка, сложное преобразование данных, и так далее).

42
Q

Redux Toolkit для чего ?

A

Redux Toolkit - это пакет, облегчающий работу с Redux.
Он был разработан для решения трех главных проблем:
1. Слишком сложная настройка хранилища (store)
2. Для того, чтобы заставить Redux делать что-то полезное, приходится использовать дополнительные пакеты
3. Слишком много шаблонного кода (boilerplate)

configureStore - это функция, предоставляемая Redux Toolkit, которая делает настройку Redux store (хранения состояния приложения). Она облегчает создание store и добавляет некоторые полезные функции по умолчанию:
1. автоматически включает расширение Redux DevTools
2. позволяет вам настраивать middleware (можно его не писать, как в обычном Редаксе)

createSlice - это функция, которая позволяет быстро создавать “slice” (часть) вашего глобального состояния в Redux.
“Slice” - это кусок вашего хранилища (store), который содержит данные и функции для их изменения.
Позволяет определить начальное состояние “slice” и функции, называемые “reducers”, которые изменяют состояние и которые принимают стейт и полезную нагрузку - payload(action), меняем все внутри мутабельно,т.к. нам это позволяет делать immerjs.
Кроме того, она автоматически генерирует action-ны для каждого редьюсера, которые вы можете использовать в своем приложении. Например:
export const appActions = slice.actions;
//вот наш созданный автоматом экшен
dispatch(appActions.setAppStatus({ status: “loading” }));
//теперь вызываем экшен
//dispatch(экшен.редьюс({ status: “loading” }));
Кстати, вывести стейт из редьюсера в консоль теперь можно таким образом: console.log(current(state))

extraReducers. Когда нам необходимо обработать case, который был создан в другом slice (т.к. не принадлежит текущему)(т.е. например, из санки диспатчится экшен, который должен обрабатываться в двух редьюсерах одновременно), тогда нам необходимо в функцию createSlice добавить свойство extraReducers. Например в task.ts:
extraReducers: builder => {
builder
.addCase(todolistsActions.addTodolist, (state, action) => {
state[action.payload.todolist.id] = []
})
// todolistsActions.addTodolist - берем экшен и редьюс из todolists.ts, а не пишем такое же название, будет ошибка.

createAsyncThunk. Санку создаем с помощью функции createAsyncThunk .
Пример:
createAsyncThunk(‘user/fetchUserData’, async (userId, thunkAPI) => {}
//’user/fetchUserData’ - это тип экшен криетеров.
Он создает автоматически action creator-ы.
Создав санку через createAsyncThunk мы автоматически создаем 2 action creator:
1 action creator вызовется когда все будет хорошо (fulfilled). Т.е. мы сделали запрос на сервер => промис успешно зарезолвился => мы попали в try или когда мы сделали запрос на сервер и res.data.resultCode === 0
2 action creator вызовется когда будет ошибка (rejected) Т.е.мы сделали запрос на сервер => промис зареджектился => мы попали в catch или когда мы сделали запрос на сервер и res.data.resultCode === 1
Какие изменения теперь при createAsyncThunk:
1. Action creator ,например, setTasksAC мы обрабатывали в slice.reducers, а теперь он будет обрабатываться в slice.extraReducers и в addCase будем передавать имя санки и вызывать у нее метод fulfilled (.addCase(fetchTasksTC.fulfilled,…). В action.payload содержится результат.
2. Action creator ,например, setTasksAC мы диспатчили, а теперь просто ретернем то, что передавали туда(то, что вернулось нам с сервера, значение зарезолвенного промиса) - return {tasks, todolistId}

Чтобы не типизировать каждый раз санку, создадим обертку над санкой в виде утилки:
export const createAppAsyncThunk = createAsyncThunk.withTypes<{
state: AppRootStateType
dispatch: AppDispatch
rejectValue: null
}>()
//теперь можем использовать createAppAsyncThunk при создании санки:
createAppAsyncThunk<{ tasks: TaskType[], todolistId: string }, string>
//просто добавляем 1 - то, что возвращает санка, 2- то, что принимает

Также помимо .addCase в extraReducers имеется метод addMatcher, который принимает два коллбэка, 1-й - это функция - предикат(возвращает либо true\false), 2-й - reducer

Пример:
extraReducers:(builder)=>{
builder.addMatcher((action) => {
return action.type.endsWith(‘/fulfilled’)
}, (state) => {
state.status = ‘succeeded’
})
//если action заканчивается на /fulfilled, то второй коллбэк выполнится, и поменяется статус крутилки.

43
Q

React.lazy и React.Suspense для чего они нужны?

A

Называется “lazy-loading” («ленивая загрузка»), другими словами, компоненты загружаются только тогда, когда они необходимы.

С помощью webpack все импортированные файлы собираются в один - это называется бандлинг.
Когда приложение разрастается, то в игру вступает разделение кода(создаются несколько бандл пакетов), которое помогает подгружать тот бандлинг, который необходим на данный момент.

Есть способ динамически отображать компоненты с помощью динамического импорта с помощью React.lazy. Он автоматически загрузит нужный бандл пакет при первой загрузке страницы.
Пример:

const ProfileContainer = lazy(() => import(‘components/Profile/ProfileContainer’));
//импорт

<Route>
<Suspense fallback={<div><Preloader></Preloader></div>}>
<ProfileContainer></ProfileContainer>
</Suspense>
</Route>

//оборачиваем компонент в Suspense. Поскольку процесс является асинхронным, компоненты с «ленивой загрузкой» должны быть заключены в компонент Suspense, который можно использовать для указания того, что модуль загружается.

44
Q

Для чего утилитные типы в TS -
Partial<T>,
Omit<T, K>,
Pick<T, K>,
Record<T, K>,
Required<T></T></T>

A
  1. Tип Partial<T> представляет объект, в котором все свойства типа T делаются необязательными путем добавления знака вопроса к каждому свойству, используя часть свойств существующего объекта.
    Пример:
    interface User {
    id: number;
    name: string;
    email: string;
    }
    const updateUser = (user: Partial<User>): void => {///}
    //Partial<User> === {id?: number; name?: string; email?: string;}</User></User></T>
  2. Тип Omit<T, K> позволяет создать новый тип, исключив определенные свойства K из типа T. Это полезно, когда вы хотите создать тип, который идентичен типу T, но без определенных свойств.
    Пример:
    interface User {
    id: number;
    name: string;
    email: string;
    age: number;
    }
    // Создаем новый тип UserWithoutId, исключив свойство ‘id’ из типа User
    type UserWithoutId = Omit<User, ‘id’>;
    //если хотим убрать два свойства, то пишем так Omit<User, ‘id’ | ‘email’>

Можно совмещать типы:
type UserWithoutId = Partial<Omit<User, ‘id’»;
//сделает необязательным свойства и уберет свойство id

  1. Tип Pick<T, K> позволяет создать новый тип, который содержит только определенные свойства K из типа T. Это полезно, когда вы хотите создать тип, который содержит только часть свойств существующего типа.
    Пример:
    interface User {
    id: number;
    name: string;
    email: string;
    age: number;
    }
    // Создаем новый тип UserInfo, включая только свойства ‘name’ и ‘email’ из типа User
    type UserInfo = Pick<User, ‘name’ | ‘email’>;
  2. Тип Record<Т, К> Он позволяет создавать объекты с определенными ключами и связанными с ними значениями, где типы ключей и значений могут быть параметризированы:
    type PhoneBook = Record<string, number>;
    const contacts: PhoneBook = {
    “Alice”: 123-456-7890,
    “Bob”: 987-654-3210,
    “Eve”: 555-123-4567
    };
    //Т - тип ключа, К- тип значения
  3. Required<T> все свойства, которые ранее были объявлены с ? (знаком вопроса) как необязательные, теперь будут обязательными.</T>

!!!!!! Эти типы можно применять только к type, к интерфейсам нет, у них другие фишки типа наследования и тп

45
Q

Отличия типов от интерфейсов?

A

В TypeScript есть два основных способа определения пользовательских структур данных: через типы (type) и через интерфейсы (interface).

Интерфейсы:
1. Интерфейсы, которые имеют одинаковое имя слияются воедино, т.е. их свойства объединяются в один интерфейс:
interface User {
id: number;
name: string;
}
interface User {
email: string;
}
const user: User = {
id: 1,
name: “Alice”,
email: “alice@example.com”
};

  1. Интерфейсы могут расширять другие интерфейсы с помощью ключевого слова extends:
    interface User {
    id: number;
    name: string;
    }
    interface ExtendedUser extends User {
    email: string;
    }
  2. Интерфейсы могут использовать декларации перегрузки для функций. Можно предоставить информацию о том, какие аргументы ожидаются и какой тип ожидается возвращаемого значения для каждого варианта вызова функции:
    interface MathOperation {
    (a: number, b: number): number; // Декларация перегрузки
    }//описывает что принимает\возвращает
    const add: MathOperation = (a, b) => a + b;
    const subtract: MathOperation = (a, b) => a - b;

Типы:
Типы могут использовать объединение (|)(ИЛИ) и пересечение (&)(И) для создания более сложных типов:
Объединение типов (|) - создает тип, который может быть либо Person, либо Employee
type PersonOrEmployee = Person | Employee;
Пересечение типов (&) - создает тип, который объединяет свойства Person и Student
type PersonAndStudent = Person & Student;
Можно использовать не только сложные типы, но и примитивы.

46
Q

В чем разница в типах any и unknown?

A

any - это тип, который предоставляет отсутствие проверки типов, не предоставляет подсказок и проверок типов, не будет предупреждать о потенциальных ошибках типов.

unknown - это более строгий тип. Нельзя выполнить ни одну операцию с переменной типа unknown без явного приведения типов или проверки типов. Нужно сначала убедиться, что тип безопасно совместим с ожидаемым типом:

let value: unknown = “Hello, TypeScript!”;
// value.toFixed(); // Ошибка компиляции, так как toFixed не существует у типа unknown

if (typeof value === “number”) {
value.toFixed(); // Ок, после проверки типа
}

47
Q

Что такое Кастомный хук?

A

Кастомный хук - это функция, которая обычно начинается с префикса “use” (например, useCustomHook), и она может содержать в себе логику состояния, эффектов (side-effects), или другую функциональность, которую вы хотите использовать в ваших компонентах.

❗Преимущества использования кастомных хуков:
1. Повторное использование логики. Когда вы создаете кастомный хук, вы можете использовать его в нескольких компонентах, что позволяет избежать дублирования кода.
2. Сокрытие деталей. Кастомный хук позволяет сокрыть детали реализации логики внутри него, делая код компонентов более чистым и понятным.
3. Упрощение компонентов. Используя кастомный хук, вы можете вынести сложную логику из компонента, делая его более простым и легко поддерживаемым.

48
Q

Что такое forwardRef?

A

это функция в React, которая позволяет передавать реф (ref) из одного компонента (child) в другой (parent) через промежуточный (intermediate) компонент.

То есть можно из родительского компонента получить доступ к ДОМ-элементу из дочерней компоненты. Оборачиваем нашу дочернюю компоненту в функцию-обертку forwardRef, принимая при этому нужные пропсы и ref.

Это позволяет вам контролировать и взаимодействовать с элементами внутри дочернего компонента из родительского компонента, несмотря на то, что дочерний компонент может быть абстрактным или самостоятельным.
Это особенно полезно в случаях, когда вы хотите управлять фокусом, анимациями, измерениями или другими характеристиками компонента-дочернего из родительского компонента.

Пример:

function ParentComponent() {
const inputRef = useRef(null);
// передающийся ref

const handleButtonClick = () => {
if (inputRef.current) {
inputRef.current.focus(); // Устанавливаем автофокус на поле ввода из родительского компонента
}
};
return (
<div>
<ChildComponent ref={inputRef} onClick={handleButtonClick} /> //передаем ref
<button onClick={handleButtonClick}>Кнопка в родительском компоненте</button>
</div>
);
}

// Компонент-дочерний элемент
const ChildComponent = forwardRef((props, ref) => { //получаем ref
return (
<div>
<input type=”text” ref={ref} /> //уставаливаем
<button onClick={props.onClick}>Кнопка внутри дочернего компонента</button>
</div>
);
});

49
Q

RTK Query, хуки

A

все эти хуки use…….Query выполняются при вмонтировании компоненты. Это нужно, чтобы избавиться от useEffect.
То есть мы получим данные на экране из data ниже сразу же как компонента вмонтируется и получит ответ от сервера.

useGetDecksQuery - используем, если нужно отталкиваться от каких то данных, например, нужно подождать пока зарезолвится один запрос прежде чем делать другой.
Используем useState:
const [skip, setSkip] = useState(true)//флаг
const { isLoading, data } = useGetDecksQuery(undefined, {
skip: skip,
//если false - то идет запрос, если true - не идет
})
function initializeQuery() {
setSkip(false)//меняет флаг
}
return (
<div>
isLoading: {isLoading.toString()}
<Button onClick={initializeQuery}>fetch</Button>
//меняет при нажатии на кнопку
{JSON.stringify(data)}
</div>
)

useLazyGetDecksQuery используем, когда нужна кнопка для получения данных, для ситуации, которая выше не подходит.

При запросе на сервер, если у нас будут запрашиваться одинаковые данные с разных компонент:
const Component1 = () => {
[limit, setLimit]=useState(5)
{user} = useFetchAllPostsQuery(limit) }

const Component2 = () => {
[limit, setLimit]=useState(5)
{user} = useFetchAllPostsQuery(limit) }

мы их отрисовываем:

<Component1>
<Component2>
По итогу отправится ТОЛЬКО один запрос, вместо двух! т.к. используемся один источник данных. Кешируются данные (полезно, когда есть выпадающие списки, которые подгружаются ассинхронно и эти списки используются в приложении повсеместно)
Но.. если например, у второй компоненты через 2 сек изменится limit на 3, то отправится запрос на лимит 3, он изменится только у этой компоненты, а у первой так и останется 10. Почему? Все из-за кеша, где 1я компонента берет данные. И его нужно в таком случае обновить.
Есть pollingInterval, который будет через определенный промежуток времени получать обновленные данные. (Лонг пуллинг)
{user} = useFetchAllPostsQuery(limit){
pollingInterval: 1000
}
Можно использовать в чатах, в уведомлениях, типа аналог websocket
Также есть функция refetch, которое модно вызывать на какое-то событие:
{user, refetch} = useFetchAllPostsQuery(limit) }
и в таком случае новые данные будет подгружать. Повесим например на кнопку
<button onClick={()=>{refetch()}}>
//при нажатии на нее будет отправляться новый запрос
</Component2></Component1>

50
Q

Что будет с браузером если функция которая сработает на событие отработает с ошибкой ?

A

Поведение браузера зависит от контекста, в котором эта функция вызывается:

  1. Обработка ошибки внутри обработчика события с try…catch:
    ошибка будет перехвачена, и браузер продолжит выполнение кода, а не завершит его из-за ошибки. Это позволяет избежать критических сбоев в работе всего веб-приложения.

document.querySelector(‘button’).addEventListener(‘click’, function () {
try {
// Код, который может вызвать ошибку
throw new Error(‘Ошибка!’);
} catch (error) {
// Обработка ошибки
console.error(error.message);
}
});

  1. Если в обработчике события не используется try…catch:
    Браузер может перестать обрабатывать другие события и выполнение JavaScript-кода может быть прервано. В зависимости от того, какие части кода нарушились, пользователь может столкнуться с непредсказуемыми сбоями или замораживанием интерфейса.
51
Q

Что можно реализовать в классах, но нельзя в функциональном реакте (error boundary,componentDidCatch) ?

A

Error Boundary - это компонент, который служит оберткой для других компонентов и предназначен для обработки ошибок, которые могут возникнуть внутри его дочерних компонентов во время рендеринга, в обработчиках событий и в методах жизненного цикла.
Основная цель Error Boundary - предотвратить падение всего React-приложения из-за ошибки внутри одного из компонентов и вместо этого отобразить заменяющий контент (fallback UI), сообщение об ошибке или выполнить другие действия по умолчанию.

Создаем такой компонент:
class ErrorBoundary extends Component {
constructor(props) {
super(props);
this.state = {
hasError: false,
error: null,
errorInfo: null
};
}

//метод, перехватывающий ошибку!!!
componentDidCatch(error, errorInfo) {
this.setState({
hasError: true,
error,
errorInfo
});
}

render() {
if (this.state.hasError) {
return (
<div>
<h2>Что-то пошло не так.</h2>
<p>{this.state.error.toString()}</p>
<div>{this.state.errorInfo.componentStack}</div>
</div>
);
}
return this.props.children;
}
}
export default ErrorBoundary;

Можно использовать этот Error Boundary вокруг любых компонентов, которые вы хотите защитить от падений приложения:

<ErrorBoundary>
<YourComponent></YourComponent>
</ErrorBoundary>

Когда компонент, обернутый Error Boundary, выбрасывает ошибку, метод componentDidCatch Error Boundary перехватывает ошибку и обновляет состояние компонента, что приводит к отображению заменяющего контента с информацией об ошибке.

НО!!!!! Они не перехватывают ошибки, которые происходят в асинхронных операциях (например, внутри setTimeout или fetch). Для обработки таких ошибок вам придется использовать другие методы, такие как try…catch.

52
Q

О реакте:

A
  1. Плюсы Реакта: 1. Производительность (без Реакта перерисовывается весь DOM, благодаря сравнению Виртуальных DOMов перерисовывается только необходимая часть DOM). 2. Масштабируемость (компоненты)
  2. Как работает Реакт (рендер-т.е. первый запуск, затем уже ререндеры): запускаем yarn start-> начнет отрисовываться index.html, запускается script->index.tsx->App.tsx (компоненты возвращают JSX)-> babel транспилятор превращает JSX в JS->создается Virtual DOM (это объект, легковесная версия DOM, у него есть только СВОЙСТВА, но нет методов, и к СВОЙСТВАМ мы доступа не имеем. DOM хранится в браузере, а Virtual DOM в оперативной памяти компьютера )->на основе Virtual DOM создается DOM, который отрисовывается в браузере. (Когда React создает новый виртуальный дом, он заменяет старый виртуальный дом ссылкой на новый объект в памяти. Garbage collector удаляет старый неактуальный виртуальный дом из-за отсутствия ссылок на него.)
  3. Разница между компонентом (функция возвращающая JSX) и Элементом (тэг). Элемент мы видим в браузере, компонент не видим.
  4. DOM (это объект-в нем есть свойства и методы) HTML-документ в виде древовидной структуры объектов (узлов). Узел- это объект в структуре дерева: элементы HTML (тэги), текст, атрибуты (src, href, class,Id, disabled, style, placeholder, required) и комментарии.
    Свойств 12:
    window - представляет окно браузера и содержит глобальный объект document.
    document - представляет целый HTML-документ.
    nodeName - имя узла.
    nodeValue - значение узла.
    Методы 8:
    createElement(tagName) - создает новый элемент указанного типа.
    getElementById(id) - возвращает элемент с указанным идентификатором.
    appendChild(node) - добавляет дочерний узел в конец списка дочерних узлов.
    removeChild(node) - удаляет указанный дочерний узел из элемента.
  5. Пропсы-это объект. Мы их передаем при помощи атрибутов (даем имя(ключ) атрибута и значение). Дочерняя компонента от родителя получает данные при помощи пропсов, а родитель при помощи колбеков.
  6. Примитив-передается по значению, объекты передается по ссылке.
  7. Ререндер компоненты происходит: когда изменяется стейт (setState), родитель изменился-это приводит к ререндеру дочерней (от изменений дочерней в родителе ничего не произойдет), и приход новых пропсов, Изменение контекста(Context Provider), Рендер это сравнение, а затем идет перерисовка.

Плюс Реакта:
-Повышение производительности приложения благодаря виртуальному DOM.
-JSX облегчает написание и чтение кода.
-Возможность рендеринга как на стороне клиента, так и на стороне сервера.
-Возможность относительно простой интеграции с фреймворками, поскольку React - это всего лишь библиотека.
-Возможность быстрого юнит и интеграционного тестирования с помощью таких инструментов, как Jest.

53
Q

Throttle и Debounce в React

A

Throttle и Debounce решают задачи оптимизации.

Throttle - пропускает вызовы функции с определённой периодичностью.
Debounce - откладывает вызов функции до того момента, когда с последнего вызова пройдёт определённое количество времени.
Например, происходят события каждый раз, как пользователь прокручивает страницу вниз:
Без: v v v v v v v //каждый раз вызывается обработчик
C Throttle: v v v v v
//через какой-то промежуток вызывается обработчик
С Debounce: v //при самом последнем событии вызывается обработчик

Примеры:

Debounce:
1. Пользователь впечатывает символы и на сервер уходит каждый напечатанный, чтобы вернуть совпадающие слова с этими символами. Так происходит без Debounce. НО… мы можем им воспользоваться и поставить таймер на 1 сек, т.е. если пользователь не будет впечатывать символы более 1 сек, то запрос уйдет на сервер. Если же 1 сек не прошло, а пользователь продолжил печатать, то таймер снова обновится на 1 сек.
2. Пользователь двигает мышкой по сайту, мы записываем координаты мышки в массив, после чего Debounce позволяет отправить информацию о перемещении мышки клиента на сервер ТОЛЬКО ПОСЛЕ того, как клиент перестаёт двигать мышкой.

function App() {
const [count, setCount] = useState(0);

const handleDebouncedClick = useCallback(
debounce(() => {
setCount(count + 1);
}, 300),
[count]
);

return (
<div>
<button onClick={handleDebouncedClick}>Debounce Click</button>
<p>Count: {count}</p>
</div>
);
}

function debounce(callback, delay) {
let timeout;
return function () {
clearTimeout(timeout);
timeout = setTimeout(callback, delay);
};
}

Throttle:
1. Если пользователь изменяет размер окна браузера и нам необходимо изменять содержимое сайта.
Без оптимизации происходит следующее. При каждом событии изменения размера окна вызывается обработчик события изменения размера окна. Таким образом, если пользователь, например, изменяет размер окна в течение 10 секунд, то может произойти 100, 200 и т.д. событий, которые нам нужно обработать.
Throttle позволяет нам задать временной интервал, чаще которого обработчик события вызываться не будет. Если мы, используя Throttle, укажем интервал в 1 секунду, то кол-во выполнения обработчиков события изменения размера окна будет равно 10.
2. Показ пользователю количества процентов прокрутки страницы. При прокрутке страницы пользователем возникают события scroll, которые нам необходимо обработать. С помощью throttle мы можем уменьшать кол-во обрабатываемых событий прокрутки пользователем страницы, задав временной интервал.

function App() {
const [count, setCount] = useState(0);

const handleThrottledClick = useCallback(
throttle(() => {
setCount(count + 1);
}, 300),
[count]
);

return (
<div>
<button onClick={handleThrottledClick}>Throttle Click</button>
<p>Count: {count}</p>
</div>
);
}

function throttle(callback, delay) {
let lastTime = 0;
return function () {
const now = Date.now();
if (now - lastTime >= delay) {
callback();
lastTime = now;
}
};
}

54
Q

useState с функцией. Обновление состояния на основе предыдущего состояния

A

function handleClick() {
setAge(age + 1); // setAge(42 + 1)
setAge(age + 1); // setAge(42 + 1)
setAge(age + 1); // setAge(42 + 1)
}
после одного клика age будет только 43, а не 45! Это происходит потому, что вызов функции set не обновляет переменную состояния age в уже запущенном коде. Поэтому каждый вызов setAge(age + 1) становится setAge(43).

Чтобы решить эту проблему, вы можете передать функцию updater в setAge вместо следующего состояния:
function handleClick() {
setAge((prev) => prev + 1); // setAge(42 => 43)
setAge((prev) => prev + 1); // setAge(43 => 44)
setAge((prev) => prev + 1); // setAge(44 => 45)
}
здесь a => a + 1 - это ваша функция обновления. Она берет отложенное состояние и вычисляет следующее состояние из него.

React помещает ваши функции обновления в очередь. Затем, во время следующего рендеринга, он будет вызывать их в том же порядке:

a => a + 1 получит 42 в качестве ожидающего состояния и вернет 43 в качестве следующего состояния.
a => a + 1 получит 43 как ожидающее состояние и вернет 44 как следующее состояние.
a => a + 1 получит 44 как состояние ожидания и вернет 45 как следующее состояние.
Других обновлений в очереди нет, поэтому в конце React сохранит 45 как текущее состояние.

55
Q

Tree Shaking

A

Tree Shaking (по-русски “тряска дерева”) - это процесс оптимизации кода в JavaScript, который используется для удаления неиспользуемых (мёртвых) частей кода (функции, переменные, модули) во время компиляции. Эта оптимизация позволяет значительно уменьшить размер итогового бандла JavaScript, что способствует более быстрой загрузке веб-приложения.

В контексте React, Tree Shaking часто применяется для оптимизации кода компонентов. Если ваше приложение имеет большое количество компонентов и библиотек, и вы используете сборщик модулей, такой как Webpack, Tree Shaking может помочь убрать неиспользуемые компоненты из финального JavaScript-бандла.

56
Q

7 методов оптимизации производительности React

A
  1. React.memo — это компонент высшего порядка (HOC), который можно использовать для предотвращения ненужных повторных рендерингов функциональных компонентов.

Обернув компонент в React.memo, вы обеспечите его повторный рендеринг только при изменении его пропсов. Это особенно полезно при работе со сложными компонентами, которые требуют больших затрат на рендеринг.

  1. Используя хук useCallback, можно мемоизировать обработчики событий, обеспечивая таким образом их изменение только при изменении зависимостей, указанных в массиве зависимостей. Это предотвращает ненужные повторные рендеринги дочерних компонентов, которые зависят от мемоизированных обработчиков событий.
  2. Важно оптимизировать производительность рендеринга длинных списков и таблиц. С помощью react-window можно эффективно отрендерить большой список, и при этом будут отображаться только видимые элементы, а количество создаваемых и обновляемых элементов DOM сократится. Эта техника, известная как “оконное управление” (“windowing”) или “виртуализация”, способна значительно повысить производительность.
    Пример:
    import { FixedSizeList as List } from ‘react-window’

const Row: React.FC<{ index: number; style: React.CSSProperties }> = ({
index,
style,
}) => {
return (
<div style={style}>
<p>{Row ${index}}</p>
</div>
)
}

const VirtualizedList: React.FC = () => {
const itemCount = 1000
return (
<List height={500} itemCount={itemCount} itemSize={50} width={300}>
{Row}
</List>
)
}

  1. Ленивая загрузка — это техника оптимизации, которая откладывает загрузку некритичных компонентов до тех пор, пока они не понадобятся. С помощью React.lazy и Suspense можно легко реализовать ленивую загрузку для компонентов. Это позволит значительно улучшить время начальной загрузки приложения за счет уменьшения количества JavaScript, который необходимо загрузить и распарсить.
    Пример:
    import React, { lazy, Suspense } from ‘react’
    const LazyLoadedComponent = lazy(() => import(‘./LazyLoadedComponent’))

const App: React.FC = () => {
return (
<div>
<Suspense fallback={<div>Loading…</div>}>
<LazyLoadedComponent></LazyLoadedComponent>
</Suspense>
</div>
)
}

  1. API для работы сReact.Profiler позволяет измерять производительность компонентов путем сбора информации о тайминге по каждой фазе рендеринга.

Используя компонент Profiler, можно определить узкие места в производительности и соответствующим образом оптимизировать приложение.
Пример:
import React, { Profiler } from ‘react’

const onRender = (
id: string,
phase: ‘mount’ | ‘update’,
actualDuration: number,
baseDuration: number,
startTime: number,
commitTime: number,
interactions: Set<{ id: number; name: string; timestamp: number }>
) => {
console.log(‘Profiler:’, {
id,
phase,
actualDuration,
baseDuration,
startTime,
commitTime,
interactions,
})
}

const App: React.FC = () => {
return (
<Profiler id=”MyComponent” onRender={onRender}>
<MyComponent></MyComponent>
</Profiler>
)
}

6.Immer — это популярная библиотека, которая упрощает работу с неизменяемыми структурами данных в JavaScript. С помощью функции produce в Immer можно написать читаемую логику обновления состояния и гарантировать, что состояние останется неизменным. Это также предотвратит непредвиденные побочные эффекты и повысит производительность.
Пример:
import produce from ‘immer’

interface User {
id: number
name: string
}

const App: React.FC = () => {
const [users, setUsers] = useState<User[]>([
{ id: 1, name: ‘Alice’ },
{ id: 2, name: ‘Bob’ },
])

const updateUser = (id: number, newName: string) => {
setUsers(
produce((draftUsers: User[]) => {
const user = draftUsers.find(user => user.id === id)
if (user) {
user.name = newName
}
})
)
}

return (
// …
)
}

  1. Троттлинг и дебаунсинг — методы, используемые для ограничения скорости выполнения функции. Это родственные, но разные понятия в контексте компьютерных наук.

Троттлинг — это прямое уменьшение скорости срабатывания. Дебаунсинг — техника поддержания частоты срабатывания ровно на 0 до периода покоя, а затем срабатывания слушателя ровно один раз.

Применяя эти техники к обработчикам ввода, можно сократить количество вызовов функций и повысить производительность, особенно при решении таких задач, как получение данных из API и фильтрация большого набора данных.

57
Q

SSR, Server-side rendering

A

рендеринг на стороне сервера (SSR, Server-side rendering) является одной из самых крутых функций React. Но она также значительно усложняет приложение.
Такие фреймворки, как Next.js, упрощают SSR, но неизбежная сложность по-прежнему остается. Для поисковой оптимизации или быстрой загрузки на мобильных устройствах обязательно используйте SSR. Но для бизнес-приложений, которые не имеют подобных требований, просто используйте рендеринг на стороне клиента.

58
Q

JWT

A

JWT (JSON Web Token) - это открытый стандарт (RFC 7519) для представления утверждений между двумя сторонами в компактном и самодостаточном виде.
JWT используется для безопасной передачи информации между клиентом и сервером, и он может быть использован для аутентификации и обмена данными в формате JSON.
JWT широко применяется в веб-разработке и аутентификации API.

JWT состоит из трех частей, разделенных точкой (.):
Заголовок (Header): Заголовок содержит информацию о том, как должен быть обработан токен (например, алгоритм шифрования). Заголовок закодирован в формате JSON и затем base64url-encoded.

Полезная нагрузка (Payload), мы сами вшиваем эти данные сюда в токен: представляют информацию, которую токен должен содержать (например, идентификатор пользователя, срок действия и другие пользовательские данные). Полезная нагрузка также закодирована в формате JSON и затем base64url-encoded.

Подпись, секретный ключ (Signature): Подпись создается путем хеширования заголовка и полезной нагрузки с использованием секретного ключа. Подпись обеспечивает аутентичность и целостность токена.
т.е. заголовок + полезная нагрузка(данные о пользователе) = все это кодируем с помощью секретного ключа.

Пример:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Срок жизни токена (Token Expiration) - это временное ограничение, установленное для JSON Web Token (JWT) или любого другого типа токена, определяющее, сколько времени токен действителен после его создания. Установка срока жизни токена - это важная мера безопасности, которая ограничивает возможность злоумышленников использовать украденный или поддельный токен для доступа к ресурсам.
Виды токенов:
access - токен доступа. Живет от 15 мин, чем меньше - тем лучше. Хранится чаще в LocalStorage
refresh - токен, который перезаписывает токен выше. Живет 15-60 дней. Т.е. если пользователь не посещал более 2х месяцев сайт, то этот токен помрет и юзеру придется снова перелогиниваться. Хранится в httpOnly Cookie. Через эти куки нельзя никак токен изменить, этот токен также записывается в БД на сервер и получается сессия.

Как работает:
пользователь пишет логин и пароль, отправляет на сервер = сервер генерирует эти два токена. Каждый записываемся сервером там, где они хранятся(LocalStorage, httpOnly Cookie) = успешно залогинились, вход ====>
далее делается запрос например, на получение сообщений(соц.сеть) + к этому запросу мы добавляем headers:
Authorization: ${accessToken}
= отправляется на сервер этот запрос и сервер проверяет валидность этого токена, не подделан ли он, не истек ли срок годности = сервер возвращает код 200 и тело запроса(что запросили)////////
если НЕ валиден токен, то возвращает код 401 и тело ‘Не авторизован!!’, например.
И на случай 401 код у нас есть перехватчик - Интерцептор(это просто функция, которая обрабатывает). Мы сразу же отправляем запрос с refresh-токеном(он уже у нас есть и на такой случай должен быть endpont для рефреша - /refresh) на обновление access-токена = сервер сверяет его с тем, что лежит в БД и если он еще годен(например, 2 месяца еще не прошло, срок жизни еще не вышел) = он возвращает новую пару токенов = и снова делается запрос на получение сообщений.
И так все по кругу, когда access-токен снова истечет, то будет сделан снова запрос с refresh-токеном и тд

59
Q

API, REST, Public

A

API (Application Programming Interface) — это код, который позволяет двум приложениям обмениваться данными с сервера.

REST (Representational State Transfer) — это способ создания API с помощью протокола HTTP.
Называют «архитектурным стилем» для операций по работе с сервером.
Например, при нажатии иконки с видео на видеохостинге REST API проводит операции и запускает ролик с сервера в браузере.
У RESTful есть 7 принципов написания кода интерфейсов:
1. Отделение клиента от сервера (Client-Server).
В REST API код запросов остается на стороне клиента, а код для доступа к данным — на стороне сервера.
2. Отсутствие записи состояния клиента
Сервер не должен хранить информацию о состоянии (проведенных операций) клиента. Каждый запрос от клиента должен содержать только ту информацию, которая нужна для получения данных от сервера.
3. Кэшируемость (Casheable). В данных запроса должно быть указано, нужно ли кэшировать данные (сохранять в специальном буфере для частых запросов). Если такое указание есть, клиент получит право обращаться к этому буферу при необходимости.
4. Единство интерфейса (Uniform Interface). Все данные должны запрашиваться через один URL-адрес стандартными протоколами, например, HTTP.
5. Многоуровневость системы (Layered System). В RESTful сервера могут располагаться на разных уровнях, при этом каждый сервер взаимодействует только с ближайшими уровнями и не связан запросами с другими.
6. Предоставление кода по запросу (Code on Demand). Серверы могут отправлять клиенту код (например, скрипт для запуска видео). Так общий код приложения или сайта становится сложнее только при необходимости.
7.Начало от нуля (Starting with the Null Style). Клиент знает только одну точку входа на сервер. Дальнейшие возможности по взаимодействию обеспечиваются сервером.

Public API:
Public — API является публичным и открытым всем.
Такие API доступны для использования общественности, и их цель — обеспечить сторонним разработчикам возможность интеграции своих приложений с определенным сервисом.
Для обеспечения безопасности и контроля доступа к данным, большинство публичных API требует аутентификации. Это может включать в себя использование API-ключей или токенов.
Чтобы разработчики могли успешно использовать API, оно должно быть хорошо задокументировано. Документация обычно включает в себя описание доступных методов, параметров, форматов данных и примеры запросов и ответов.
Примеры публичных API включают в себя API социальных сетей (например, Twitter API, Facebook Graph API), API картографических сервисов (например, Google Maps API), API финансовых данных (например, Yahoo Finance API), и многие другие. Публичные API позволяют разработчикам создавать приложения, интегрированные с различными сервисами, расширяя их функциональность и взаимодействуя с данными, предоставляемыми этими сервисами.

60
Q

какую проблему решает БЭМ?

A

БЭМ, что расшифровывается как “Блок, Элемент, Модификатор”, представляет собой методологию именования классов в HTML и CSS для создания модульного и масштабируемого кода в веб-разработке.
Проблему решает:
1. Снижение вероятности конфликтов стилей: Использование уникальных именованных классов для каждого блока и элемента уменьшает вероятность конфликтов стилей между различными компонентами проекта
2. Улучшение сотрудничества в команде: БЭМ стандартизирует именование классов, что облегчает совместную работу в команде разработчиков. Каждый разработчик может легко понять структуру и именование классов, используемых в проекте.
3. Повторное использование кода: Методология БЭМ способствует созданию переиспользуемых компонентов. Блоки и элементы могут быть использованы на разных страницах проекта или даже в различных проектах, что упрощает разработку и обслуживание.
4. Ясная структура и читаемость кода: Использование четкой иерархии классов, основанной на БЭМ, упрощает чтение и понимание кода для разработчиков. Каждый блок, элемент и модификатор имеют явные имена, что делает код более понятным и облегчает сопровождение.
5. Масштабируемость: БЭМ предоставляет структуру именования классов, которая легко масштабируется при разработке больших и сложных проектов. Модульность и явное разделение компонентов в виде блоков и элементов позволяют управлять кодом более эффективно.

61
Q

что такое семантика и доступность?

A

Семантика в веб-разработке относится к использованию HTML-тегов и их атрибутов согласно их предназначению и смыслу. Это означает, что разметка веб-страницы должна отражать не только её визуальное оформление, но и смысловую структуру содержимого. Использование семантических элементов, таких как <header>, <nav>, <main>, <article>, <section>, <footer> и других, помогает браузерам, поисковым системам и вспомогательным технологиям лучше понимать структуру страницы и её содержание.

Доступность:
Семантическая разметка делает веб-сайты более доступными для людей с ограниченными возможностями, так как вспомогательные технологии (например, программы чтения с экрана) могут лучше воспринимать структуру и смысл страницы.

Все про доступность приложения - атрибуты, семантические теги, где они должны находится(хедер, футер, нав и тд):
https://my-js.org/docs/cheatsheet/web-accessibility/#%D1%82%D0%B5%D1%81%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5

Все теги с примерами их применения:
https://my-js.org/docs/cheatsheet/html5#%D1%82%D0%B0%D0%B1%D0%BB%D0%B8%D1%86%D0%B0-

62
Q

если все микротаски выполнятся а дальше пойдут макротаски, внутри которого есть микротаск, то что вызовется макро или микротаск

A

Если в процессе выполнения макрозадачи внутри нее возникает новая микрозадача (например, промис), эта микрозадача будет поставлена в очередь микрозадач и выполнится сразу же после завершения текущей макрозадачи.

console.log(‘Start of the script’);

// Макрозадача (setTimeout)
setTimeout(() => {
console.log(‘Inside setTimeout (macrotask)’);

// Микрозадача (Promise)
Promise.resolve().then(() => {
    console.log('Inside Promise (microtask)');
});
  
console.log('End of setTimeout (macrotask)'); }, 0);

console.log(‘End of the script’);

“Start of the script”
“End of the script”
“Inside setTimeout (macrotask)”
“End of setTimeout (macrotask)”
“Inside Promise (microtask)”

63
Q

какие источники стилей применяются к веб-странице помимо нашего

A

—Браузерные стили (User Agent Styles): Браузер применяет свои собственные стандартные стили к элементам HTML для обеспечения базового отображения веб-страниц. Эти стили различаются в зависимости от браузера, но они предоставляют стандартные значения для элементов, таких как заголовки, параграфы, списки и т.д.
—Пользовательские стили (User Styles): Пользователи могут определить собственные стили для веб-страниц с использованием инструментов, предоставляемых браузерами. Например, расширения браузера могут позволять пользователям настраивать стили для конкретных сайтов.
—-Стили из других источников (CDN, внешние таблицы стилей): Веб-страница может использовать внешние таблицы стилей, например, хранящиеся на удаленных серверах с использованием Content Delivery Network (CDN). Это может включать в себя библиотеки стилей, такие как Bootstrap, Font Awesome и др.
—-Инлайн-стили (Inline Styles): Стили могут быть применены непосредственно внутри тегов HTML с использованием атрибута style. Эти стили будут иметь более высокий приоритет, чем стили из внешних таблиц.
—-Стили из JavaScript: С помощью JavaScript можно динамически изменять стили на веб-странице. Например, это может быть сделано с использованием метода style DOM API или добавлением/удалением классов элементов.
—-Медиа-запросы (Media Queries): Стили могут быть адаптивными и изменяться в зависимости от характеристик устройства или экрана с использованием медиа-запросов в CSS.
—-Стили из других источников внутри iframe: Если ваша страница содержит iframe, то стили внутри этого iframe могут применяться независимо от стилей на основной странице.

64
Q

какой селектор будем использовать если захотим применить стиль ко всем

A

Если вы хотите применить стиль ко всем элементам на веб-странице, вы можете использовать универсальный селектор *. Этот селектор выбирает все элементы на странице и позволяет вам применить стили ко всем ним.

65
Q

для чего нужны ключи в Реакте

A

key - это специальный строковый атрибут, который следует использовать при создании списков элементов. Проп key помогает React определять, какие элементы подверглись изменениям, были добавлены или удалены.
Чаще всего в качестве ключа (key) мы используем id,
индексы тоже можно использовать, но не рекомендуется.

В контексте React ключи (keys) играют важную роль в процессе согласования (reconciliation).

Они помогают React идентифицировать, какие элементы были добавлены, изменены или удалены.

React использует ключи для эффективного сравнения старого и нового состояния массива и обновления только тех элементов, которые действительно изменились.

66
Q

разница между useState useRef

A

useState:
—Состояние компонента: useState предназначен для управления состоянием функциональных компонентов в React. Он предоставляет возможность добавления состояния в функциональные компоненты, что ранее было прерогативой классовых компонентов.
—Перерисовка компонента: Использование useState приводит к перерисовке компонента при изменении состояния. Когда состояние изменяется с помощью setState, компонент перерисовывается, а новое состояние становится доступным.

useRef:
—-Ссылки на элементы: useRef предназначен для создания и хранения мутабельных (изменяемых) объектов, которые могут переживать изменения без вызова перерисовки компонента. Он часто используется для получения доступа к DOM-элементам или для сохранения данных между рендерами без вызова перерисовки.
—–Не вызывает перерисовку: Изменения в объекте, созданном с помощью useRef, не вызывают перерисовку компонента. Поэтому это удобный способ хранения данных между рендерами без перерисовки.

67
Q

useRef

A

Создание ссылки:
function ExampleComponent() {
const myRef = useRef();
return <div ref={myRef}>Пример компонента</div>;
}
Здесь myRef - это объект ссылки, который можно использовать для доступа к DOM-элементу (в данном случае, <div>).

Сохранение мутабельных значений между рендерами:
function ExampleComponent() {
const count = useRef(0);
//не будет вызывать ререндер при изменении состояния
useEffect(() => {
count.current = count.current + 1;
console.log(Значение count: ${count.current});
}, []);

return <div>Пример компонента</div>;
}
В этом примере useRef используется для сохранения и изменения значения count между рендерами компонента. Значение count.current может изменяться без вызова перерисовки.

Ссылки на DOM-элементы:
function AutoFocusInput() {
const inputRef = useRef();

useEffect(() => {
inputRef.current.focus(); // Фокус на поле ввода при монтировании компонента
}, []);

return <input ref={inputRef} />;
}
Здесь inputRef используется для создания ссылки на DOM-элемент (в данном случае, <input></input>), чтобы можно было легко получить доступ к его методам, таким как focus().

Передача ref дочернему компоненту:
function ChildComponent({ forwardedRef }) {
return <input ref={forwardedRef} />;
}

function ParentComponent() {
const inputRef = useRef();

return <ChildComponent forwardedRef={inputRef} />;
}
Здесь useRef используется для создания ссылки в родительском компоненте, а затем передается как пропс в дочерний компонент. Таким образом, родительский компонент может управлять ссылкой на элемент, созданной дочерним компонентом.

.current содержит текущее значение useRefа, или содержит ссылку на узел DOM
например:
const myRef = useRef();
console.log(myRef.current); // Выведет текущее значение ref = undefined,т.к оно не определено
myRef.current = “Новое значение”; // Изменение значения ref
console.log(myRef.current); // Выведет “Новое значение”

68
Q

хук useId

A

Он возвращает нам уникальный id, который выглядит следующим образом: :r1:, :r2:, :r3: Странность данного формата id думаю и помогает быть ему более уникальным на странице.
Например, связываем лейбел и инпут
const id = useId();
return (
<div>
<label htmlFor={id}>Some input</label>
<InfoIcon onClick={onClick} />
<input name=”some-input” id={id} />
</div>
);
};

Теперь давайте ответим на вопрос, почему этот хук должен был стать частью React экосистемы. Почему бы не использовать просто npm пакет uuid или вообще не генерировать его с помощью Math.random.

Ответ достаточно простой - Server Side Rendering. Как мы все знаем React теперь выполняется не только на клиенте, но еще и на сервере. Что произойдет, если мы сгенерируем id через uuid. Оно выдаст одно значение на сервере. И когда произойдет первый рендер уже на клиенте, то мы увидим, что id изменился. И как следствие мы увидим вот такую ошибку в консоли.

Это значит что атрибут id на сервере и на клиенте не совпали. И что делать с этой ошибкой непонятно ведь никакие useState, useMemo или другие хуки не помогут вам решить эту проблему. Придется как то хардкодить такого рода id-шники.

React же взял эту проблему на себя. И предоставил нам магический хук useId. Который работает в любых условиях. У вас Single Page Application - не проблема. Или у вас Server Side Rendering - тоже не вопрос, а может вы ультрамодные и используете Server Components - это тоже не проблема. useId будет работать в любых условиях.

69
Q

Разница между контролируемыми и неконтролируемыми компонентами ?

A

В HTML элементы формы, такие как <input></input>, <textarea> и <select>, обычно поддерживают собственное состояние и обновляют его в соответствии с пользовательскими входными данными. В React изменяемое состояние обычно хранится в свойстве state компонентов и обновляется только с помощью setState(), либо с помощью хука useState().</select></textarea>

В управляемом компоненте с каждым изменением состояния связанна функция обработчик, а сами обновляемы данные хранятся внутри свойства компонента state, благодаря этому механизму, данные внутри этого компонента могут быть доступны за его пределами и с ними можно легко взаимодействовать.

Неуправляемые компоненты опираются на DOM в качестве источника данных, другими словами это обычные HTML элементы, которые обновляются динамически, инкапсулируют данные внутри себя и никак не связанны с React.

70
Q

Перечислите особенности React?

A

Ключевые особенности React:
- декларативность,
- универсальность( можно использовать на сервере и на мобильных платформах с помощью React Native),
- компонентный подход(возможность переиспользовать компоненты),
- виртуальный DOM,
- JSX.
- SSR(server site rendering) - поддержка рендеринга на стороне сервера.
- Однонаправленный поток данных(все данные передаются от корневых компонентов во вложенные, но не обратно)

71
Q

Что такое контекст (Context)?

A

Контекст позволяет передавать данные через дерево компонентов без необходимости передавать пропсы на промежуточных уровнях.
Сейчас используется хук useContext();

72
Q

Что такое React хуки (Hooks)?

A

Хуки — механизм в React, который позволяет работать полностью без классов. Он не приносит ничего нового, но облегчает повторное использование кода для решения общих задач. Сейчас это основной способ написания React-приложений. Но хуки не заменяют собой классы целиком.

Здесь можно посмотреть уже готовые хуки, не библиотечные
https://my-js.org/docs/cheatsheet/custom-hooks#usewindowsize

Здесь можно посмотреть готовые компоненты, типа аккордион, пароль, карусель
https://my-js.org/docs/cheatsheet/custom-components#accordion

73
Q

что такое политика CORS

A

для управления доступом к ресурсам вашего сайта из других источников.
Т.е. например, если нет доступа у нашего приложения к данным сервера, который защищен CORS, то мы не получим эти данные и будет ошибка

74
Q

React.Fragment для чего

A

Иногда возникает ситуация, когда вы хотите вернуть несколько элементов без создания дополнительного DOM-контейнера. Вот где React.Fragment приходит на помощь.

Или более короткая форма, используя пустые угловые скобки <> и </>:

React.Fragment полезен, когда вам нужно вернуть несколько элементов без добавления дополнительного уровня DOM(без создания доп узла), что особенно важно в некоторых случаях, например, при работе с компонентами высшего порядка или возвращении списка элементов.

75
Q

Тестирование UI-компонентов с помощью
“@testing-library/jest-dom”,
“@testing-library/react”,
“@testing-library/user-event”

A

Тестирования React-компонента с использованием React Testing Library.

@testing-library/user-event - это дополнительная библиотека к @testing-library/react, предоставляющая удобные средства для эмуляции пользовательских событий в тестах. Она упрощает взаимодействие с компонентами, созданными с использованием React, путем эмуляции действий пользователя, таких как клики, ввод текста, клавишные нажатия и т. д.

userEvent.click(element, options?): Имитирует клик по элементу.

userEvent.dblClick(element, options?): Имитирует двойной клик по элементу.

userEvent.type(element, text, options?): Имитирует ввод текста в элемент. text - строка текста для ввода.

userEvent.clear(element): Имитирует очистку содержимого ввода.

userEvent.selectOptions(selectElement, values): Имитирует выбор одного или нескольких вариантов в элементе <select>.</select>

userEvent.upload(element, files): Имитирует загрузку файлов в элемент <input></input>.

userEvent.hover(element): Имитирует наведение курсора на элемент.

userEvent.unhover(element): Имитирует убирание курсора с элемента.

userEvent.focus(element): Имитирует фокусировку на элементе.

userEvent.blur(element): Имитирует потерю фокуса элементом.

userEvent.keyboard(…events): Имитирует набор клавиш.

userEvent.paste(element, text, options?): Имитирует вставку текста в элемент.