Перейти к основному содержимому

200 вопросов по React

200 вопросов по React

Основы React

Вопрос

Что такое React?

Ответ

React — это JavaScript-библиотека для создания пользовательских интерфейсов, разработанная Facebook. Она позволяет строить компонентные, декларативные и эффективные UI-приложения.


Вопрос

Какие основные преимущества использования React?

Ответ

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


Вопрос

Что такое компонент в React?

Ответ

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


Вопрос

Какие типы компонентов существуют в React?

Ответ

В React существуют функциональные компоненты и классовые компоненты. Функциональные компоненты — это обычные JavaScript-функции, возвращающие JSX. Классовые компоненты наследуются от React.Component и могут содержать состояние и методы жизненного цикла.


Вопрос

Что такое JSX?

Ответ

JSX — это расширение синтаксиса JavaScript, позволяющее писать HTML-подобные конструкции внутри JavaScript-кода. JSX транспилируется в вызовы React.createElement().


Вопрос

Можно ли использовать React без JSX?

Ответ

Да, React можно использовать без JSX, напрямую вызывая React.createElement(). Однако JSX делает код более читаемым и удобным для разработки.


Вопрос

Что такое Virtual DOM?

Ответ

Virtual DOM — это легковесная копия реального DOM в виде дерева JavaScript-объектов. React использует его для вычисления минимального количества изменений, необходимых для обновления реального DOM.


Вопрос

Как работает процесс рендеринга в React?

Ответ

При изменении состояния или пропсов React создаёт новое дерево Virtual DOM, сравнивает его с предыдущим (процесс reconciliation), определяет минимальный набор изменений и применяет их к реальному DOM.


Вопрос

Что такое пропсы (props)?

Ответ

Пропсы — это входные данные, передаваемые компоненту извне. Они неизменяемы внутри компонента и используются для конфигурации его поведения и внешнего вида.


Вопрос

Можно ли изменять props внутри компонента?

Ответ

Нет, props являются неизменяемыми. Любые попытки изменения props нарушают принцип одностороннего потока данных в React.


Вопрос

Что такое состояние (state) компонента?

Ответ

Состояние — это объект, содержащий данные, специфичные для компонента и изменяющиеся во времени. Изменение состояния вызывает повторный рендер компонента.


Вопрос

Как обновляется состояние в функциональных компонентах?

Ответ

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

const [count, setCount] = useState(0);
setCount(count + 1);

Вопрос

Как обновляется состояние в классовых компонентах?

Ответ

Состояние в классовых компонентах обновляется с помощью метода this.setState(). Этот метод принимает объект или функцию и планирует обновление состояния.

this.setState({ count: this.state.count + 1 });

Вопрос

Является ли вызов setState синхронным?

Ответ

Вызов setState асинхронный. React может группировать несколько вызовов setState для повышения производительности.


Вопрос

Что такое односторонний поток данных в React?

Ответ

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


Вопрос

Что такое ключ (key) в списках React?

Ответ

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


Вопрос

Почему важно использовать уникальные ключи?

Ответ

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


Вопрос

Можно ли использовать индекс массива как ключ?

Ответ

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


Вопрос

Что такое условный рендеринг в React?

Ответ

Условный рендеринг — это техника отображения разных компонентов или элементов в зависимости от состояния или пропсов. Реализуется с помощью операторов if, тернарного оператора или логического &&.

{isLoggedIn ? <UserGreeting /> : <GuestGreeting />}

Вопрос

Как обрабатываются события в React?

Ответ

События в React обрабатываются с помощью обработчиков, передаваемых как props. Имена событий пишутся в camelCase, а обработчики — это функции, а не строки.

<button onClick={handleClick}>Нажми</button>

Хуки (Hooks)

Вопрос

Что такое хуки в React?

Ответ

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


Вопрос

Какие встроенные хуки предоставляет React?

Ответ

React предоставляет встроенные хуки: useState, useEffect, useContext, useReducer, useCallback, useMemo, useRef, useImperativeHandle, useLayoutEffect, useDebugValue.


Вопрос

Что делает хук useState?

Ответ

Хук useState добавляет локальное состояние в функциональный компонент. Он возвращает пару: текущее значение состояния и функцию для его обновления.


Вопрос

Что делает хук useEffect?

Ответ

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


Вопрос

Когда срабатывает эффект без зависимостей?

Ответ

Эффект без массива зависимостей срабатывает после каждого рендера компонента.

useEffect(() => {
document.title = 'Обновлено';
});

Вопрос

Когда срабатывает эффект с пустым массивом зависимостей?

Ответ

Эффект с пустым массивом зависимостей срабатывает один раз после начального рендера, аналогично componentDidMount.

useEffect(() => {
console.log('Смонтировано');
}, []);

Вопрос

Как очистить побочный эффект?

Ответ

Очистка побочного эффекта выполняется путём возврата функции из useEffect. Эта функция вызывается перед размонтированием компонента или перед следующим запуском эффекта.

useEffect(() => {
const subscription = subscribe();
return () => subscription.unsubscribe();
}, []);

Вопрос

Что делает хук useContext?

Ответ

Хук useContext позволяет подписаться на контекст React и получать его текущее значение. При изменении значения провайдера все компоненты, использующие useContext, перерисовываются.

const theme = useContext(ThemeContext);

Вопрос

Что делает хук useReducer?

Ответ

Хук useReducer управляет сложным состоянием с помощью функции-редьюсера. Он принимает редьюсер и начальное состояние, возвращает текущее состояние и функцию dispatch.

const [state, dispatch] = useReducer(reducer, initialState);

Вопрос

Когда стоит использовать useReducer вместо useState?

Ответ

useReducer предпочтителен при управлении сложным состоянием с несколькими подзначениями или когда логика обновления состояния зависит от предыдущего состояния.


Вопрос

Что делает хук useCallback?

Ответ

Хук useCallback возвращает мемоизированную версию функции. Он полезен для предотвращения ненужных перерисовок дочерних компонентов, ожидающих стабильные ссылки на функции.

const memoizedCallback = useCallback(() => {
doSomething(a, b);
}, [a, b]);

Вопрос

Что делает хук useMemo?

Ответ

Хук useMemo возвращает мемоизированное значение. Он используется для дорогостоящих вычислений, которые должны выполняться только при изменении зависимостей.

const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

Вопрос

В чём разница между useCallback и useMemo?

Ответ

useCallback мемоизирует функцию, а useMemo мемоизирует результат вызова функции. useCallback(fn, deps) эквивалентен useMemo(() => fn, deps).


Вопрос

Что делает хук useRef?

Ответ

Хук useRef создаёт mutable-объект, свойство .current которого сохраняется между рендерами. Он используется для доступа к DOM-элементам или хранения любого изменяемого значения без вызова повторного рендера.

const inputRef = useRef(null);
// ...
<input ref={inputRef} />

Вопрос

Можно ли использовать хуки внутри условий или циклов?

Ответ

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


Вопрос

Что такое пользовательские хуки?

Ответ

Пользовательские хуки — это функции JavaScript, начинающиеся с use, которые вызывают другие хуки. Они позволяют извлекать и повторно использовать логику компонентов.

function useLocalStorage(key, initialValue) {
const [value, setValue] = useState(() => {
// логика инициализации
});
// ...
return [value, setValue];
}

Вопрос

Какие правила применения хуков существуют?

Ответ

Существуют два правила:

  1. Хуки вызываются только на верхнем уровне компонента.
  2. Хуки вызываются только из React-компонентов или других хуков.

Вопрос

Можно ли вызывать хуки из обычных функций?

Ответ

Нет, хуки можно вызывать только из React-компонентов или других пользовательских хуков.


Вопрос

Как React связывает хуки с компонентом?

Ответ

React связывает хуки с компонентом по порядку их вызова. Сохранение этого порядка между рендерами гарантирует корректную работу внутреннего механизма хуков.


Вопрос

Что происходит при нарушении правил хуков?

Ответ

При нарушении правил хуков возникают ошибки несоответствия состояния между рендерами, что приводит к непредсказуемому поведению компонентов.


Компоненты и их жизненный цикл

Вопрос

Какие методы жизненного цикла есть в классовых компонентах?

Ответ

Основные методы жизненного цикла:

  • constructor — инициализация состояния,
  • render — возврат JSX,
  • componentDidMount — выполнение после монтирования,
  • componentDidUpdate — выполнение после обновления,
  • componentWillUnmount — очистка перед размонтированием.

Вопрос

Что делает метод componentDidMount?

Ответ

Метод componentDidMount вызывается сразу после того, как компонент вставлен в DOM. Он используется для инициализации, таких как загрузка данных или установка подписок.


Вопрос

Что делает метод componentDidUpdate?

Ответ

Метод componentDidUpdate вызывается сразу после обновления компонента. Он принимает предыдущие props и state и используется для выполнения операций в ответ на изменения.


Вопрос

Что делает метод componentWillUnmount?

Ответ

Метод componentWillUnmount вызывается перед удалением компонента из DOM. Он используется для отмены таймеров, отписки от событий и освобождения ресурсов.


Вопрос

Есть ли жизненный цикл у функциональных компонентов?

Ответ

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


Вопрос

Как заменить componentDidMount с помощью хуков?

Ответ

componentDidMount заменяется эффектом с пустым массивом зависимостей:

useEffect(() => {
// логика монтирования
}, []);

Вопрос

Как заменить componentDidUpdate с помощью хуков?

Ответ

componentDidUpdate заменяется эффектом с зависимостями. Для доступа к предыдущим значениям используется useRef.

useEffect(() => {
// сработает при изменении prop
}, [prop]);

Вопрос

Как заменить componentWillUnmount с помощью хуков?

Ответ

componentWillUnmount заменяется функцией очистки, возвращаемой из useEffect.

useEffect(() => {
return () => {
// логика размонтирования
};
}, []);

Вопрос

Что такое чистый компонент (PureComponent)?

Ответ

PureComponent — это базовый класс для классовых компонентов, который реализует поверхностное сравнение props и state для предотвращения ненужных рендеров.


Вопрос

Как работает React.memo?

Ответ

React.memo — это HOC, который мемоизирует функциональный компонент. Он предотвращает повторный рендер, если props не изменились.

const MemoizedComponent = React.memo(MyComponent);

Вопрос

Когда стоит использовать React.memo?

Ответ

React.memo стоит использовать для компонентов, которые рендерятся часто, но редко меняют свои props, особенно если они дороги в рендере.


Вопрос

Что такое высокоуровневый компонент (HOC)?

Ответ

Высокоуровневый компонент — это функция, принимающая компонент и возвращающая новый компонент с дополнительной функциональностью.


Вопрос

Приведите пример HOC.

Ответ

function withLoading(WrappedComponent) {
return function WithLoading(props) {
if (props.isLoading) return <div>Загрузка...</div>;
return <WrappedComponent {...props} />;
};
}

Вопрос

Что такое render props?

Ответ

Render props — это паттерн, при котором компонент принимает функцию в качестве prop и вызывает её для рендера. Эта функция получает данные и возвращает JSX.

<DataProvider render={data => <h1>{data.target}</h1>} />

Вопрос

В чём преимущество render props перед HOC?

Ответ

Render props обеспечивают большую гибкость в композиции, позволяют избежать обёртывания компонентов в глубокие иерархии и работают без создания новых компонентов на каждый случай.


Вопрос

Что такое порталы (Portals) в React?

Ответ

Порталы позволяют рендерить дочерний элемент в DOM-узел, находящийся вне иерархии родительского компонента. Используются для модальных окон, всплывающих подсказок и тултипов.

ReactDOM.createPortal(child, domNode);

Вопрос

Как создать портал?

Ответ

Портал создаётся с помощью ReactDOM.createPortal(child, container), где child — это JSX-элемент, а container — DOM-узел, в который нужно вставить элемент.


Вопрос

Что происходит с событиями в порталах?

Ответ

События в порталах всплывают в иерархии React-компонентов, а не в DOM-иерархии. Это позволяет обрабатывать события в родительских компонентах, даже если элемент отрендерен вне их DOM-контейнера.


Вопрос

Что такое фрагменты (Fragments) в React?

Ответ

Фрагменты позволяют группировать список дочерних элементов без добавления лишнего узла в DOM. Используются синтаксис <></> или <React.Fragment>.

<>
<ChildA />
<ChildB />
</>

Вопрос

Почему фрагменты полезны?

Ответ

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


Вопрос

Что такое forwardRef?

Ответ

forwardRef — это функция, позволяющая передавать ref через компонент к одному из его дочерних элементов. Это необходимо для доступа к DOM-узлу извне обёрнутого компонента.

const FancyButton = React.forwardRef((props, ref) => (
<button ref={ref} className="fancy">{props.children}</button>
));

Вопрос

Когда используется forwardRef?

Ответ

forwardRef используется при создании компонентов-обёрток, таких как HOC или компоненты с логикой, которые должны предоставлять доступ к внутреннему DOM-элементу.


Вопрос

Что такое children в React?

Ответ

children — это специальный prop, содержащий содержимое, переданное между открывающим и закрывающим тегами компонента. Доступен через props.children.

<Parent>Это children</Parent>

Вопрос

Как работать с children?

Ответ

children можно рендерить напрямую, фильтровать, преобразовывать или клонировать с помощью утилит из React.Children.

function MyComponent({ children }) {
return <div>{children}</div>;
}

Вопрос

Что делает React.cloneElement?

Ответ

React.cloneElement клонирует и возвращает элемент, добавляя к нему новые props. Используется для модификации дочерних элементов, переданных через children.

React.cloneElement(child, { newProp: 'value' });

Вопрос

Что такое Error Boundary?

Ответ

Error Boundary — это компонент, который перехватывает ошибки JavaScript в любом месте дерева компонентов, логирует их и отображает резервный UI вместо аварийного фрагмента.


Вопрос

Как создать Error Boundary?

Ответ

Error Boundary создаётся как классовый компонент с методами static getDerivedStateFromError и/или componentDidCatch.

class ErrorBoundary extends React.Component {
state = { hasError: false };
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, info) {
logError(error, info);
}
render() {
return this.state.hasError ? <FallbackUI /> : this.props.children;
}
}

Вопрос

Перехватывает ли Error Boundary все ошибки?

Ответ

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


Вопрос

Можно ли использовать Error Boundary в функциональных компонентах?

Ответ

Нет, Error Boundary можно реализовать только в классовых компонентах, так как они требуют методов жизненного цикла, недоступных в функциях.


Вопрос

Что такое строгий режим (Strict Mode) в React?

Ответ

Strict Mode — это инструмент для выявления потенциальных проблем в приложении. Он активирует дополнительные проверки и предупреждения в режиме разработки.

<React.StrictMode>
<App />
</React.StrictMode>

Вопрос

Какие проверки выполняет Strict Mode?

Ответ

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


Управление состоянием и контекст

Вопрос

Что такое подъём состояния (lifting state up)?

Ответ

Подъём состояния — это паттерн, при котором общее состояние перемещается в ближайший общий родительский компонент. Это позволяет синхронизировать данные между несколькими дочерними компонентами.


Вопрос

Когда следует поднимать состояние?

Ответ

Состояние следует поднимать, когда несколько компонентов должны отображать или изменять одни и те же данные. Это обеспечивает единый источник истины и предотвращает рассогласованность.


Вопрос

Что такое Context API в React?

Ответ

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


Вопрос

Как создаётся контекст в React?

Ответ

Контекст создаётся с помощью React.createContext(defaultValue). Он возвращает объект с Provider и Consumer.

const ThemeContext = React.createContext('light');

Вопрос

Как использовать Provider?

Ответ

Provider оборачивает часть дерева компонентов и передаёт значение контекста всем дочерним компонентам, которые к нему подписаны.

<ThemeContext.Provider value="dark">
<App />
</ThemeContext.Provider>

Вопрос

Как читать значение контекста в функциональном компоненте?

Ответ

Значение контекста читается с помощью хука useContext.

const theme = useContext(ThemeContext);

Вопрос

Можно ли использовать несколько контекстов?

Ответ

Да, в приложении можно использовать множество независимых контекстов. Они не конфликтуют между собой.


Вопрос

Какие недостатки у Context API?

Ответ

Context API вызывает повторный рендер всех подписанных компонентов при любом изменении значения, даже если они используют только часть данных. Это может снижать производительность при частых обновлениях.


Вопрос

Как избежать лишних ререндеров при использовании контекста?

Ответ

Разделять контексты по смыслу, мемоизировать значение с помощью useMemo, и выносить часто меняющиеся данные в отдельный контекст.


Вопрос

Что такое «провайдер-паттерн»?

Ответ

Провайдер-паттерн — это архитектурный подход, при котором данные предоставляются через Provider, а потребляются через useContext или Consumer. Он централизует управление состоянием.


Роутинг (React Router)

Вопрос

Какой пакет используется для роутинга в React?

Ответ

Для роутинга в React используется пакет react-router-dom.


Вопрос

Какие основные компоненты предоставляет React Router?

Ответ

Основные компоненты: BrowserRouter, Routes, Route, Link, NavLink, Navigate, Outlet, useNavigate, useParams, useLocation.


Вопрос

Что делает компонент BrowserRouter?

Ответ

BrowserRouter использует HTML5 History API для синхронизации UI с URL-адресом. Он должен оборачивать всё приложение.


Вопрос

Как определить маршрут?

Ответ

Маршрут определяется с помощью компонента Route внутри Routes. Указывается путь и элемент, который нужно отрендерить.

<Routes>
<Route path="/home" element={<Home />} />
</Routes>

Вопрос

Как перейти по ссылке без перезагрузки страницы?

Ответ

Используется компонент Link. Он предотвращает стандартное поведение <a> и обновляет историю через History API.

<Link to="/about">О нас</Link>

Вопрос

Как программно изменить маршрут?

Ответ

Программный переход выполняется с помощью хука useNavigate.

const navigate = useNavigate();
navigate('/profile');

Вопрос

Как получить параметры маршрута?

Ответ

Параметры маршрута получаются с помощью хука useParams.

// маршрут: /user/:id
const { id } = useParams();

Вопрос

Как получить текущий URL?

Ответ

Текущий URL получается с помощью хука useLocation.

const location = useLocation(); // { pathname, search, hash, ... }

Вопрос

Что такое вложенные маршруты?

Ответ

Вложенные маршруты — это маршруты, определённые внутри других маршрутов. Они позволяют строить иерархическую структуру UI.

<Route path="dashboard" element={<Dashboard />}>
<Route path="stats" element={<Stats />} />
</Route>

Вопрос

Как отрендерить дочерние маршруты?

Ответ

Дочерние маршруты отображаются с помощью компонента Outlet внутри родительского компонента.

function Dashboard() {
return (
<div>
<h1>Панель</h1>
<Outlet />
</div>
);
}

Вопрос

Как сделать редирект?

Ответ

Редирект выполняется с помощью компонента Navigate или функции navigate(..., { replace: true }).

<Route path="/old" element={<Navigate to="/new" replace />} />

Вопрос

Что такое NavLink?

Ответ

NavLink — это специальная версия Link, которая автоматически добавляет класс или стиль, когда её путь совпадает с текущим URL.

<NavLink to="/home" className={({ isActive }) => isActive ? 'active' : ''}>
Главная
</NavLink>

Вопрос

Как защитить маршрут?

Ответ

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

function ProtectedRoute({ children }) {
const isAuthenticated = useAuth();
return isAuthenticated ? children : <Navigate to="/login" />;
}

Вопрос

Поддерживает ли React Router серверный рендеринг?

Ответ

Да, React Router работает с серверным рендерингом, но требует использования StaticRouter на сервере вместо BrowserRouter.


Вопрос

Как обрабатывать несуществующие маршруты?

Ответ

Несуществующие маршруты обрабатываются с помощью Route без path или с path="*".

<Route path="*" element={<NotFound />} />

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

Вопрос

Какие факторы влияют на производительность React-приложения?

Ответ

Производительность зависит от частоты ререндеров, сложности компонентов, объёма DOM-дерева, количества подписок и побочных эффектов.


Вопрос

Что такое мемоизация в React?

Ответ

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


Вопрос

Как работает React.memo?

Ответ

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


Вопрос

Когда стоит использовать React.memo?

Ответ

React.memo полезен для компонентов, которые рендерятся часто, но редко меняют свои props, особенно если они дороги в рендере.


Вопрос

Что делает useMemo?

Ответ

useMemo мемоизирует значение, вычисленное функцией. Оно пересчитывается только при изменении зависимостей.

const expensiveValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

Вопрос

Что делает useCallback?

Ответ

useCallback мемоизирует функцию. Это предотвращает создание новой функции при каждом рендере, что важно при передаче в дочерние компоненты.

const handleClick = useCallback(() => doSomething(), []);

Вопрос

Почему стабильные ссылки на функции важны?

Ответ

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


Вопрос

Как измерить производительность компонента?

Ответ

Можно использовать React DevTools Profiler, console.time, или обёртку с performance.now() внутри useEffect.


Вопрос

Что такое lazy loading в React?

Ответ

Lazy loading — это отложенная загрузка компонентов до момента их фактического отображения. Реализуется с помощью React.lazy и Suspense.

const LazyComponent = React.lazy(() => import('./LazyComponent'));
<Suspense fallback={<Spinner />}>
<LazyComponent />
</Suspense>

Вопрос

Как работает React.lazy?

Ответ

React.lazy принимает функцию, возвращающую промис с модулем, содержащим компонент по умолчанию. Он позволяет динамически импортировать компоненты.


Вопрос

Можно ли использовать React.lazy для именованных экспортов?

Ответ

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


Вопрос

Что такое code splitting?

Ответ

Code splitting — это разделение кода на отдельные бандлы, которые загружаются по мере необходимости. Это уменьшает начальный размер загружаемого JavaScript.


Вопрос

Как избежать «waterfall» при загрузке данных?

Ответ

Запускать запросы данных как можно раньше — до или параллельно рендеру компонента, например, с помощью библиотек вроде Relay или Suspense-enabled fetchers.


Вопрос

Что такое virtualization списка?

Ответ

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


Вопрос

Какие библиотеки реализуют virtualization?

Ответ

Популярные библиотеки: react-window, react-virtualized.


Вопрос

Как оптимизировать длинные списки?

Ответ

Использовать ключи, React.memo для элементов списка, и virtualization для отрисовки только видимых элементов.


Вопрос

Почему ключи должны быть стабильными?

Ответ

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


Вопрос

Как избежать inline-функций в рендере?

Ответ

Выносить функции за пределы компонента или мемоизировать их с помощью useCallback.


Вопрос

Что такое batching в React?

Ответ

Batching — это группировка нескольких вызовов setState в один ререндер. В React 18 batching применяется даже для асинхронных обработчиков.


Вопрос

Как отключить batching?

Ответ

Batching можно отключить с помощью flushSync из react-dom.

import { flushSync } from 'react-dom';
flushSync(() => {
setA(1);
setB(2);
});

Тестирование React-компонентов

Вопрос

Какие основные библиотеки используются для тестирования React-приложений?

Ответ

Основные библиотеки: Jest (фреймворк для запуска тестов), React Testing Library (рендер и взаимодействие с компонентами), и иногда Cypress или Playwright для E2E-тестов.


Вопрос

Что такое React Testing Library?

Ответ

React Testing Library — это набор утилит для тестирования компонентов React так, как это делает пользователь. Она поощряет тестирование поведения, а не реализации.


Вопрос

Как рендерить компонент в тесте?

Ответ

Компонент рендерится с помощью функции render из @testing-library/react.

const { getByText } = render(<Button />);

Вопрос

Как найти элемент в DOM во время теста?

Ответ

Элементы находятся с помощью query-функций: getBy*, queryBy*, findBy*. Например, getByText, getByRole, getByTestId.


Вопрос

В чём разница между getBy и queryBy?

Ответ

getBy выбрасывает ошибку, если элемент не найден. queryBy возвращает null, если элемент отсутствует. Это полезно для проверки отсутствия элемента.


Вопрос

Как дождаться асинхронного рендера?

Ответ

Асинхронный рендер ожидается с помощью findBy* или waitFor.

const { findByText } = render(<AsyncComponent />);
await findByText('Загружено');

Вопрос

Как имитировать клик по кнопке?

Ответ

Клик имитируется с помощью fireEvent.click.

const { getByText } = render(<Button />);
fireEvent.click(getByText('Нажми'));

Вопрос

Как проверить вызов колбэка?

Ответ

Колбэк заменяется мок-функцией через jest.fn(), и после взаимодействия проверяется, был ли он вызван.

const handleClick = jest.fn();
render(<Button onClick={handleClick} />);
fireEvent.click(screen.getByText('Нажми'));
expect(handleClick).toHaveBeenCalled();

Вопрос

Как тестировать компонент с контекстом?

Ответ

Компонент оборачивается в провайдер контекста при рендере.

render(
<ThemeContext.Provider value="dark">
<ThemedButton />
</ThemeContext.Provider>
);

Вопрос

Как тестировать компонент с роутингом?

Ответ

Компонент оборачивается в MemoryRouter из react-router-dom.

render(
<MemoryRouter initialEntries={['/profile']}>
<App />
</MemoryRouter>
);

Вопрос

Что такое snapshot-тестирование?

Ответ

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


Вопрос

Когда уместно использовать snapshot-тесты?

Ответ

Snapshot-тесты уместны для стабильных компонентов без логики, например, простых UI-блоков или error boundary.


Вопрос

Как тестировать эффекты (useEffect)?

Ответ

Эффекты тестируются косвенно через их побочные действия: изменение DOM, вызов API (мокнутого), обновление состояния.


Вопрос

Как мокать модули в Jest?

Ответ

Модули мокаются с помощью jest.mock.

jest.mock('./api', () => ({
fetchData: () => Promise.resolve({ data: 'test' })
}));

Вопрос

Как проверить, что компонент корректно обрабатывает ошибки?

Ответ

Оборачивают компонент в Error Boundary и проверяют отображение резервного UI после выброса ошибки в дочернем компоненте.


Concurrent Mode и Suspense

Вопрос

Что такое Concurrent Mode в React?

Ответ

Concurrent Mode — это набор возможностей React, позволяющих приложению оставаться отзывчивым, прерывая и возобновляя рендер по мере необходимости.


Вопрос

Включён ли Concurrent Mode по умолчанию в React 18?

Ответ

В React 18 Concurrent Mode не включён глобально, но многие его возможности доступны автоматически через новый корневой API (createRoot).


Вопрос

Как включить Concurrent Mode?

Ответ

Concurrent Mode включается при создании корня с помощью createRoot вместо render.

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);

Вопрос

Что такое Suspense?

Ответ

Suspense — это механизм React для отложенной загрузки данных или кода. Он позволяет показывать fallback-UI, пока дочерний компонент не будет готов.


Вопрос

Как использовать Suspense для lazy-компонентов?

Ответ

Lazy-компонент оборачивается в Suspense с fallback.

const LazyComp = React.lazy(() => import('./LazyComp'));
<Suspense fallback={<Spinner />}>
<LazyComp />
</Suspense>

Вопрос

Можно ли использовать Suspense для данных?

Ответ

Да, но только если источник данных поддерживает интеграцию с Suspense (например, Relay, Apollo с экспериментальной поддержкой, или кастомные кэши).


Вопрос

Что такое «transition» в React?

Ответ

Transition — это способ пометить обновление состояния как несрочное. React может прервать его, чтобы сначала обработать более приоритетные обновления (например, ввод текста).


Вопрос

Как использовать переходы?

Ответ

Переходы используются с помощью хука useTransition.

const [isPending, startTransition] = useTransition();
startTransition(() => {
setSearchQuery(input);
});

Вопрос

Что делает useDeferredValue?

Ответ

useDeferredValue откладывает обновление части UI, чтобы сохранить отзывчивость основного интерфейса.

const deferredQuery = useDeferredValue(query);

Вопрос

В чём разница между useTransition и useDeferredValue?

Ответ

useTransition управляет началом отложенного обновления, а useDeferredValue автоматически создаёт отложенную копию значения и управляет её актуальностью.


Серверный рендеринг (SSR)

Вопрос

Что такое серверный рендеринг (SSR)?

Ответ

Серверный рендеринг — это процесс генерации HTML на сервере и отправки готового содержимого клиенту. Это улучшает SEO и время первой отрисовки.


Вопрос

Какой метод используется для SSR в React?

Ответ

Для SSR используется renderToString из react-dom/server.

const html = renderToString(<App />);

Вопрос

Что такое гидратация?

Ответ

Гидратация — это процесс подключения клиентского JavaScript к серверному HTML, чтобы сделать его интерактивным.


Вопрос

Как выполнить гидратацию на клиенте?

Ответ

На клиенте используется hydrateRoot (в React 18) вместо render.

const root = hydrateRoot(document.getElementById('root'), <App />);

Вопрос

Какие данные нужно передавать при SSR?

Ответ

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


Вопрос

Что такое несоответствие между сервером и клиентом?

Ответ

Несоответствие возникает, когда серверный и клиентский рендер производят разный HTML. React выдаёт предупреждение и перерисовывает всё на клиенте.


Вопрос

Как избежать несоответствия?

Ответ

Избегать использования window, localStorage, Date.now() и других клиентских API в рендере. Условный рендер на основе typeof window !== 'undefined'.


Вопрос

Поддерживает ли useEffect SSR?

Ответ

useEffect не выполняется на сервере, так как серверный рендер синхронный и не имеет побочных эффектов.


Вопрос

Какие фреймворки упрощают SSR в React?

Ответ

Next.js — самый популярный фреймворк для SSR и SSG в React. Он автоматизирует сбор данных, роутинг и гидратацию.


Вопрос

Можно ли использовать useState с начальным значением от сервера?

Ответ

Да, начальное значение useState может быть получено из props, которые пришли с сервера.

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

Архитектура и лучшие практики

Вопрос

Что такое «единственный источник истины»?

Ответ

«Единственный источник истины» — это принцип, согласно которому каждая часть состояния хранится в одном месте и передаётся через props или контекст.


Вопрос

Где хранить состояние: в локальном состоянии или в глобальном?

Ответ

Состояние хранится локально, если оно используется только в одном компоненте. Если оно нужно в нескольких местах, его поднимают или выносят в глобальное хранилище.


Вопрос

Когда использовать Redux вместо Context API?

Ответ

Redux предпочтителен при сложной логике обновления состояния, middleware (логгирование, саги), частых обновлениях, и необходимости высокой производительности при большом числе подписчиков.


Вопрос

Что такое presentational и container-компоненты?

Ответ

Presentational-компоненты отвечают за внешний вид и получают данные через props. Container-компоненты управляют логикой, состоянием и подключаются к хранилищу.


Вопрос

Актуален ли паттерн presentational/container сегодня?

Ответ

Паттерн менее популярен, так как хуки позволяют легко разделять логику и UI без явного разделения компонентов.


Вопрос

Как организовать структуру проекта на React?

Ответ

Распространённые подходы: по функциональности (feature-sliced), по типу файлов (components, pages, hooks), или гибридный. Главное — последовательность и масштабируемость.


Вопрос

Что такое custom hook?

Ответ

Custom hook — это функция с префиксом use, которая инкапсулирует повторно используемую логику с использованием других хуков.


Вопрос

Как именовать custom hooks?

Ответ

Custom hooks именуются с префикса use, например useLocalStorage, useDebounce, useFetch.


Вопрос

Что такое «побочный эффект» в React?

Ответ

Побочный эффект — это любая операция, выходящая за рамки чистого рендера: запросы к API, подписки, изменение DOM, таймеры.


Вопрос

Почему важно очищать эффекты?

Ответ

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


Работа с формами

Вопрос

Какие типы форм используются в React?

Ответ

В React используются контролируемые (controlled) и неконтролируемые (uncontrolled) формы.


Вопрос

Что такое контролируемый компонент?

Ответ

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

<input value={value} onChange={e => setValue(e.target.value)} />

Вопрос

Что такое неконтролируемый компонент?

Ответ

Неконтролируемый компонент — это элемент формы, который хранит своё состояние внутренне. Значение извлекается с помощью ref.

const inputRef = useRef();
// ...
<input defaultValue="initial" ref={inputRef} />
console.log(inputRef.current.value);

Вопрос

Когда использовать неконтролируемые компоненты?

Ответ

Неконтролируемые компоненты уместны при интеграции с не-React-кодом, при работе с файловыми input'ами или когда требуется минимальное управление состоянием.


Вопрос

Как обрабатывать отправку формы?

Ответ

Отправка формы обрабатывается через onSubmit, где вызывается event.preventDefault(), чтобы предотвратить перезагрузку страницы.

<form onSubmit={e => { e.preventDefault(); handleSubmit(); }}>
<input />
<button type="submit">Отправить</button>
</form>

Вопрос

Как реализовать валидацию формы?

Ответ

Валидация реализуется в обработчике onChange или onSubmit. Результат сохраняется в состоянии и отображается пользователю.


Вопрос

Какие библиотеки помогают работать с формами?

Ответ

Популярные библиотеки: Formik, React Hook Form, Final Form. React Hook Form особенно эффективен благодаря минимальному количеству ререндеров.


Вопрос

Почему React Hook Form быстрее других?

Ответ

React Hook Form использует неконтролируемые компоненты по умолчанию и минимизирует использование состояния, что снижает количество ререндеров.


Вопрос

Как сбросить форму в React?

Ответ

Форма сбрасывается вызовом reset() на DOM-элементе или установкой начальных значений состояния.

const [values, setValues] = useState(initial);
const resetForm = () => setValues(initial);

Вопрос

Как обработать множественный выбор (select multiple)?

Ответ

Значение select multiple — массив. Обновление выполняется через фильтрацию или добавление в массив.

<select multiple value={selected} onChange={e => setSelected([...e.target.selectedOptions].map(o => o.value))}>

TypeScript и React

Вопрос

Как типизировать props функционального компонента?

Ответ

Props типизируются с помощью интерфейса или типа, передаваемого как дженерик в FC или напрямую в сигнатуру функции.

interface Props { name: string; age: number; }
const User: React.FC<Props> = ({ name, age }) => <div>{name}, {age}</div>;

Вопрос

Нужно ли использовать React.FC?

Ответ

Использование React.FC не обязательно. Прямая типизация параметров функции считается более прозрачной и гибкой.

const User = ({ name, age }: Props) => <div>{name}, {age}</div>;

Вопрос

Как типизировать useState?

Ответ

Тип состояния указывается как дженерик в useState.

const [count, setCount] = useState<number>(0);

Вопрос

Как типизировать useRef?

Ответ

Тип ref указывается как дженерик в useRef.

const inputRef = useRef<HTMLInputElement>(null);

Вопрос

Как типизировать useReducer?

Ответ

Типизируются состояние и action с помощью интерфейсов или union-типов.

type State = { count: number };
type Action = { type: 'increment' } | { type: 'decrement' };
const reducer = (state: State, action: Action): State => { /* ... */ };
const [state, dispatch] = useReducer(reducer, initialState);

Вопрос

Как типизировать контекст?

Ответ

Контекст типизируется при создании с помощью дженерика.

const ThemeContext = createContext<'light' | 'dark'>('light');

Вопрос

Как избежать ошибки "Object is possibly null" с ref?

Ответ

Проверять наличие ref.current перед использованием или использовать утверждение ненулевого значения (!), если уверены в его наличии.

if (inputRef.current) inputRef.current.focus();
// или
inputRef.current!.focus();

Вопрос

Как типизировать custom hook?

Ответ

Custom hook типизируется через возвращаемое значение и параметры.

function useLocalStorage<T>(key: string, initialValue: T): [T, (value: T) => void] {
// ...
}

Вопрос

Как типизировать children?

Ответ

Children типизируются как React.ReactNode.

interface Props { children: React.ReactNode; }

Вопрос

Поддерживает ли JSX TypeScript?

Ответ

Да, TypeScript имеет встроенную поддержку JSX и проверяет корректность тегов, props и типов.


Совместимость, миграции и экосистема

Вопрос

С какими версиями React совместим современный код?

Ответ

Современный код, использующий хуки, требует React 16.8 или выше. Concurrent-функции требуют React 18+.


Вопрос

Как мигрировать с классовых компонентов на функциональные?

Ответ

Миграция выполняется пошагово: замена методов жизненного цикла на useEffect, состояние — на useState или useReducer, рефы — на useRef.


Вопрос

Можно ли использовать классовые и функциональные компоненты вместе?

Ответ

Да, React полностью поддерживает смешанное использование классовых и функциональных компонентов в одном приложении.


Вопрос

Что такое create-react-app?

Ответ

Create React App — это официальный инструмент для быстрого старта React-приложений без конфигурации сборки.


Вопрос

Актуален ли create-react-app сегодня?

Ответ

Create React App остаётся простым решением для обучения и небольших проектов, но для сложных сценариев чаще выбирают Vite, Next.js или кастомную сборку.


Вопрос

Какие альтернативы есть у create-react-app?

Ответ

Популярные альтернативы: Vite (быстрая сборка), Next.js (SSR/SSG), Remix (сервер-центричная архитектура).


Вопрос

Поддерживает ли React Web Components?

Ответ

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


Вопрос

Можно ли использовать React в мобильной разработке?

Ответ

Да, с помощью React Native, который использует те же принципы, но рендерит нативные компоненты вместо DOM.


Вопрос

Что такое React Server Components?

Ответ

React Server Components — это экспериментальная технология, позволяющая рендерить компоненты на сервере без отправки JavaScript клиенту, уменьшая размер бандла.


Вопрос

Где можно использовать Server Components?

Ответ

Server Components доступны в Next.js 13+ и требуют специального окружения. Они не заменяют клиентские компоненты, а дополняют их.


Internals и продвинутые темы

Вопрос

Что такое Fiber в React?

Ответ

Fiber — это внутренняя архитектура React, введённая в React 16. Она позволяет разбивать работу на части, приостанавливать и возобновлять рендер для повышения отзывчивости.


Вопрос

Что такое reconciliation?

Ответ

Reconciliation — это процесс сравнения нового Virtual DOM с предыдущим для определения минимального набора изменений в реальном DOM.


Вопрос

Как React определяет, нужно ли обновлять компонент?

Ответ

React сравнивает props и state. Для классовых компонентов можно переопределить shouldComponentUpdate. Для функциональных — использовать React.memo.


Вопрос

Что такое «чистая функция» в контексте рендера?

Ответ

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


Вопрос

Почему нельзя вызывать хуки внутри условий?

Ответ

Порядок вызова хуков должен быть одинаковым между рендерами. Условный вызов нарушает этот порядок и приводит к ошибкам.


Вопрос

Что происходит при вызове setState с тем же значением?

Ответ

React выполняет поверхностное сравнение. Если значение не изменилось, повторный рендер может быть пропущен.


Вопрос

Как работает key при перемещении элементов списка?

Ответ

React использует key для сопоставления элементов между рендерами. При перемещении элемента с тем же key его DOM-узел перемещается, а не пересоздаётся.


Вопрос

Можно ли использовать объекты как ключи?

Ответ

Нет, ключ должен быть строкой или числом. Объекты преобразуются в "[object Object]", что делает их непригодными для уникальной идентификации.


Вопрос

Что такое «стабильный идентификатор»?

Ответ

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


Вопрос

Как отладить производительность в продакшене?

Ответ

Используются инструменты: React DevTools Profiler (в development), метрики Web Vitals, и кастомные метрики через Performance API.


Практические сценарии и edge cases

Вопрос

Как обновить состояние на основе предыдущего значения?

Ответ

Передать функцию в setState или set из useState.

setCount(prev => prev + 1);

Вопрос

Как избежать бесконечного цикла в useEffect?

Ответ

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


Вопрос

Как передать данные между несвязанными компонентами?

Ответ

Использовать Context API, глобальное состояние (Redux, Zustand), или поднять состояние до ближайшего общего предка.


Вопрос

Как реализовать debounce в React?

Ответ

Использовать useEffect с таймером и useCallback для стабильной функции.

function useDebounce(value, delay) {
const [debounced, setDebounced] = useState(value);
useEffect(() => {
const handler = setTimeout(() => setDebounced(value), delay);
return () => clearTimeout(handler);
}, [value, delay]);
return debounced;
}

Вопрос

Как отслеживать изменения в глубоком объекте?

Ответ

Использовать useMemo для создания сериализованной строки или библиотеку для глубокого сравнения, такую как lodash.isEqual, внутри useEffect.


Вопрос

Как сделать компонент «невидимым» для accessibility?

Ответ

Добавить aria-hidden="true" и tabIndex={-1}.


Вопрос

Как обеспечить focus management в модальном окне?

Ответ

При открытии модального окна фокус перемещается внутрь, и trapped с помощью useEffect и обработчика keydown для Tab.


Вопрос

Как обрабатывать resize окна?

Ответ

Использовать useEffect с подпиской на событие resize и очисткой.

useEffect(() => {
const handleResize = () => { /* ... */ };
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);

Вопрос

Как загрузить скрипт динамически?

Ответ

Создать элемент <script> в useEffect и удалить его при размонтировании.


Вопрос

Как протестировать компонент с setTimeout?

Ответ

Использовать jest.useFakeTimers() и act для управления временем в тестах.

jest.useFakeTimers();
render(<Component />);
act(() => jest.advanceTimersByTime(1000));