Фронтенд-разработчик React (Профессиональный уровень)
Учебная программа курса «Фронтенд-разработчик React (Профессиональный уровень)» включает углубленное изучение библиотеки React и современных инструментов фронтенд-разработки. Курс состоит из следующих модулей:
- Продвинутый React — работа с хуками (useState, useEffect, useReducer, пользовательские хуки), управление контекстом через Context API, оптимизация рендеринга компонентов.
- Redux Toolkit — архитектура состояния, slice, thunk, работа с нормализованным состоянием.
- TypeScript в React — типизация компонентов, пропсов, событий, хуков, работа с generics и пересечениями типов.
- React Router v6+ — маршрутизация на продвинутом уровне, ленивая загрузка страниц, защита маршрутов, параметры URL.
- Работа с API — запросы через Axios и Fetch, обработка ошибок, кэширование данных с помощью React Query, SWR.
- Тестирование — написание unit- и интеграционных тестов с использованием Jest, React Testing Library, snapshot-тестирование.
- Оптимизация производительности — memoization, code splitting, серверный рендеринг (Next.js), работа с Webpack и Babel.
- Практика построения SPA — разработка масштабируемого приложения от проектирования архитектуры до деплоя.
Ожидаемые результаты после прохождения курса:
Должен уметь:
- Разрабатывать высоконагруженные одностраничные приложения на React.
- Применять TypeScript для обеспечения надежности кода.
- Управлять состоянием приложений с Redux Toolkit и Context API.
- Оптимизировать производительность React-приложений.
- Реализовывать маршрутизацию, асинхронную работу с данными и обработку ошибок.
- Писать автоматизированные тесты для компонентов и бизнес-логики.
- Интегрироваться с REST/GraphQL API.
- Строить архитектурно устойчивые приложения, соответствующие best practices.
Должен знать:
- Принципы работы React-компонента и жизненного цикла.
- Механизмы управления состоянием (Redux Toolkit, Context API).
- Нюансы типизации в TypeScript применительно к React.
- Современные подходы к маршрутизации, мемоизации и асинхронной обработке.
- Подходы к структурированию проекта и разделению ответственности.
- Основы SSR и SSG на примере Next.js.
-
Что такое React и для чего он используется?
React — это JavaScript-библиотека с открытым исходным кодом для создания пользовательских интерфейсов, особенно одностраничных приложений (SPA). Она позволяет разрабатывать интерактивные UI-компоненты декларативно, используя подход «один раз написал — можно использовать везде». React абстрагирует работу с DOM, упрощает обновление интерфейса при изменении состояния и предоставляет мощный механизм компонентной архитектуры. -
В чём разница между классовыми и функциональными компонентами в React?
Классовые компоненты — это ES6-классы, расширяющиеReact.Component
поддерживают состояние черезthis.state
и жизненные циклыcomponentDidMount
componentDidUpdate
Функциональные компоненты — это обычные JS-функции, которые принимают props и возвращают JSX. С появлением хуков (например,useState
useEffect
функциональные компоненты стали более популярными благодаря простоте и возможности управления состоянием без классов. -
Что такое JSX и как он работает в React?
JSX (JavaScript XML) — это синтаксическое расширение JavaScript, позволяющее писать HTML-подобную разметку прямо в JavaScript-коде. При помощи Babel JSX преобразуется в вызовыReact.createElement()
Это делает создание UI более удобным и читаемым. Например:<div>Hello</div>
превращается вReact.createElement('div', null, 'Hello')
-
Как управлять состоянием в React?
Состояние (state) в React управляется с помощью хуковuseState
useReducer
или классовых методовthis.state
this.setState
Хуки предоставляют более простой способ работы со state в функциональных компонентах. Для сложных приложений рекомендуется использовать Redux Toolkit или Context API сuseReducer
-
Что такое props и как их использовать?
Props (сокращение от properties) — это данные, передаваемые от родительского компонента к дочернему. Они неизменны внутри дочернего компонента. Props позволяют создавать переиспользуемые компоненты, например:<UserCard name="Alice" age={25} />
-
Как работает useEffect в React?
ХукuseEffect
позволяет выполнять побочные эффекты в функциональных компонентах. Он аналогиченcomponentDidMount
componentDidUpdate
componentWillUnmount
в классовых компонентах. Пример: загрузка данных, подписка на события, мутации DOM. Второй аргумент — массив зависимостей, определяющий, когда запускать эффект. -
Что такое ключи (keys) в списке компонентов и зачем они нужны?
Keys помогают React идентифицировать, какие элементы списка изменились, добавились или удалились. Это улучшает производительность рендеринга. Keys должны быть уникальными среди соседних элементов, но не обязательно глобально. Обычно используются ID из базы данных. -
Что такое контекст (Context API) и как его использовать?
Context API позволяет передавать данные через дерево компонентов без необходимости явно передавать props на каждом уровне. Используется для передачи данных, доступных во всем приложении (например, тема, язык, авторизация). Создается с помощьюReact.createContext()
и используется черезProvider
иuseContext
-
Что такое хуки (hooks) и какие ограничения у них есть?
Хуки — это функции, которые позволяют использовать состояние и другие возможности React в функциональных компонентах. Ограничения: нельзя вызывать хуки внутри условий, циклов, вложенных функций; хуки можно вызывать только на верхнем уровне компонента или других хуков. -
Как тестировать React-компоненты?
Для тестирования используются Jest и React Testing Library. Пишутся unit-тесты, интеграционные тесты, snapshot-тесты. Тестируются такие аспекты, как отображение, обработка событий, взаимодействие с API. Пример: проверить, что кнопка вызывает нужный обработчик при клике. -
Что такое React.memo и когда его использовать?
React.memo
— это HOC, который предотвращает повторный рендер компонента, если props не изменились. Полезен для оптимизации производительности. По умолчанию сравнивает props поверхностно, но можно передать свою функцию сравнения. -
Что такое useMemo и useCallback?
useMemo
возвращает мемоизированное значение, которое пересчитывается только при изменении зависимостей.useCallback
возвращает мемоизированную функцию. Оба полезны для оптимизации, особенно при передаче колбэков в оптимизированные дочерние компоненты. -
Как работать с формами в React?
Формы в React могут управляться черезcontrolled components
(состояние хранится в React),uncontrolled components
(через ref), либо библиотеки вроде Formik, React Hook Form. Лучше использовать контролируемые компоненты для лучшей контроль над данными и валидацией. -
Что такое маршрутизация в React и как её реализовать?
Маршрутизация реализуется черезreact-router-dom
Поддерживает SPA-навигацию без перезагрузки страницы. Используются компонентыBrowserRouter
Route
Link
Navigate
В v6+ маршруты объявляются через объект или вложенную структуру. -
Что такое Redux и зачем он нужен?
Redux — это шаблон управления состоянием приложения, основанный на принципах однонаправленного потока данных. Он централизует состояние приложения, обеспечивает предсказуемость изменений и упрощает отладку. Используется вместе сreact-redux
для интеграции с React. -
Что такое Redux Toolkit и чем он отличается от классического Redux?
Redux Toolkit — официальная библиотека для упрощения работы с Redux. Упрощает создание хранилища, редьюсеров и экшенов. Автоматически иммутабельно мутирует состояние (через Immer), включаетcreateSlice
createAsyncThunk
configureStore
Рекомендуется для новых проектов вместо "чистого" Redux. -
Как отправлять HTTP-запросы в React?
HTTP-запросы можно отправлять черезfetch
axios
swr
react-query
Axios удобен из-за поддержки async/await, автоматической сериализации ответа и перехватчиков. React Query помогает кэшировать данные, управлять повторными запросами и фоновым обновлением. -
Что такое TypeScript и как он используется в React?
TypeScript — это надмножество JavaScript с поддержкой типов. В React он позволяет строго типизировать props, состояние, события, хуки. Это улучшает читаемость кода, снижает количество ошибок и повышает качество автодополнения в IDE. -
Как организовать структуру проекта на React?
Распространённые подходы: по функционалуfeatures/
entities/
shared/
по слоямcomponents/
containers/
services/
по модулямauth/
profile/
layout/
Также часто используются шаблоны типа Feature-Sliced Design. Главное — соблюдать принцип разделения ответственности и переиспользования. -
Что такое SSR и SSG и как они реализуются в React?
SSR (Server Side Rendering) — рендеринг на сервере, затем отправка готовой HTML-страницы клиенту. SSG (Static Site Generation) — генерация статических HTML-файлов на этапе сборки. Реализуются через Next.js, Gatsby. Улучшают SEO и время загрузки страницы. -
Как оптимизировать производительность React-приложения?
Оптимизация включает: использованиеReact.memo
useMemo
useCallback
ленивую загрузкуReact.lazy
Suspense
code splitting, правильное управление состоянием, минимизацию rerender, профилирование через React DevTools Profiler. -
Как работать с изображениями и медиа в React?
Изображения можно импортировать как модулиimport logo from './logo.png'
или использовать URL-адреса. Для оптимизации используютсяnext/image
gatsby-image
WebP-форматы, lazy loading, адаптивные изображения. -
Как деплоить React-приложение?
Приложения можно деплоить через Vercel, Netlify, GitHub Pages, Firebase Hosting, AWS Amplify. Для этого используетсяnpm run build
после чего файлы изbuild/
загружаются на хостинг. Настройка DNS, домена, CI/CD также важна. -
Как использовать CSS в React?
CSS можно подключать глобально, использовать CSS-модули, styled-components, Emotion, Tailwind CSS. Каждый подход имеет свои преимущества: модульность, темизация, inline-стили, utility-first. -
Как организовать аутентификацию в React-приложении?
Аутентификация может быть реализована через JWT, OAuth, Firebase Auth, Auth0. Данные пользователя хранятся в состоянии, localStorage, context или Redux. Защита маршрутов реализуется через HOC илиuseNavigate
в React Router.
-
Что такое порталы (Portals) в React и как их использовать?
Порталы позволяют рендерить дочерние элементы вне иерархии DOM-компонента, но сохраняя контекст React. Используются для модальных окон, тултипсов, уведомлений. Реализуются черезReactDOM.createPortal(child, container)
-
Как обрабатывать ошибки в React-компонентах?
Для обработки ошибок используются Error Boundaries — классовые компоненты с методамиstatic getDerivedStateFromError()
илиcomponentDidCatch()
Они перехватывают ошибки в дочерних компонентах и могут отображать fallback UI вместо краха. -
Что такое асинхронные действия в Redux и как они работают?
Асинхронные действия — это действия, которые выполняются не сразу, а после завершения асинхронной операции (например, HTTP-запроса). В Redux Toolkit используетсяcreateAsyncThunk
для создания таких действий. Он автоматически генерирует типы экшеновpending
fulfilled
rejected
и позволяет обрабатывать результат в редьюсере. -
Как реализовать ленивую загрузку (lazy loading) в React?
Ленивая загрузка реализуется черезReact.lazy()
иSuspense
Например:const LazyComponent = React.lazy(() => import('./LazyComponent'))
Компонент будет загружен только при первом рендере.Suspense
отображает fallback во время загрузки. -
Что такое высокопроизводительные компоненты (Pure Components) в React?
Pure Component — это классовый компонент, который автоматически реализуетshouldComponentUpdate
и сравнивает текущие props и state с предыдущими поверхностно. Это помогает избежать ненужных перерисовок. В функциональных компонентах аналог —React.memo
-
Как работает механизм reconciliation в React?
Reconciliation — это процесс сравнения нового виртуального DOM с предыдущим для определения минимального количества изменений в реальном DOM. React использует алгоритм diffing, основанный на предположении, что деревья сильно отличаются редко, поэтому он работает за O(n). -
Что такое фрагменты (Fragments) и зачем они нужны?
Фрагменты позволяют группировать несколько элементов без добавления лишнего узла в DOM. Используются как<React.Fragment>...</React.Fragment>
или короткая запись<>...</>
Полезны, когда нужно вернуть несколько корневых элементов. -
Как передавать данные между несвязанными компонентами в React?
Для передачи данных между несвязанными компонентами можно использовать Context API, Redux, Zustand, MobX или глобальный event bus. Лучше всего подходят Context + useReducer для средних приложений и Redux / Zustand для больших. -
Что такое HOC (Higher-Order Component) и как его создать?
HOC — это функция, которая принимает компонент и возвращает новый компонент с дополнительными props или поведением. Пример:function withLogger(WrappedComponent) { return function(props) { console.log('Rendered'); return <WrappedComponent {...props} />; } }
-
Как использовать пользовательские хуки (custom hooks)?
Пользовательские хуки — это функции, начинающиеся сuse
которые могут вызывать другие хуки. Позволяют выносить логику состояния и эффектов в переиспользуемый код. Пример:useFetch
useLocalStorage
useFormValidation
-
Как работать с localStorage в React?
localStorage можно использовать черезlocalStorage.getItem()
localStorage.setItem()
localStorage.removeItem()
Для синхронизации с React-состоянием часто применяетсяuseEffect
иuseState
с начальным значением из localStorage. -
Что такое Webpack и как он используется в React-проектах?
Webpack — это сборщик модулей, который объединяет JavaScript, CSS, изображения и другие ресурсы в один или несколько бандлов. В React-проектах он настраивается черезwebpack.config.js
и управляет code splitting, lazy loading, loaders и plugins. -
Как использовать Babel в React-приложениях?
Babel преобразует современный JavaScript (ES6+) в совместимый с более старыми браузерами. В React используется для преобразования JSX вReact.createElement()
-вызовы. Конфигурация осуществляется через.babelrc
илиbabel.config.js
-
Как организовать работу с переменными окружения в React?
Переменные окружения задаются в файле.env
, напримерREACT_APP_API_URL=http://api.example.com
Доступ к ним осуществляется черезprocess.env.REACT_APP_API_URL
Переменные должны начинаться сREACT_APP_
-
Что такое серверный рендеринг (SSR) и как он влияет на SEO?
Серверный рендеринг (SSR) позволяет генерировать HTML-страницу на сервере, что улучшает индексацию поисковыми системами (SEO). В React SSR реализуется через Next.js, где страницы рендерятся на сервере с помощьюgetServerSideProps
-
Как использовать TypeScript с Redux Toolkit?
TypeScript обеспечивает строгую типизацию для состояния, экшенов и селекторов. При использованииcreateSlice
можно указать тип состояния и тип payload. Также используетсяcreateSelector
изreselect
для мемоизации и типизации селекторов. -
Что такое микротаски и макротаски в JavaScript и как это связано с useEffect в React?
Микротаски (Promise.then, MutationObserver) имеют приоритет над макротасками (setTimeout, setInterval, I/O). ХукuseEffect
выполняется после рендера, но до следующего цикла событий. Это важно для понимания порядка выполнения кода и side-effects. -
Как реализовать debounce и throttle в React с помощью хуков?
Debounce и throttle можно реализовать с помощьюuseCallback
setTimeout
иuseRef
Например,useDebounce(value, delay)
возвращает значение с задержкой. Это полезно для поиска, скролла, изменения размера окна. -
Что такое suspense и как он используется в React?
Suspense
позволяет показывать fallback UI (например, спиннер) во время ожидания асинхронной операции, такой как ленивая загрузка компонента. Поддерживается черезReact.lazy()
В будущем может поддерживать и другие асинхронные задачи. -
Как реализовать internationalization (i18n) в React-приложении?
Для i18n используются библиотеки, такие какreact-i18next
formatjs
linguijs
Они позволяют менять язык интерфейса динамически, форматировать даты, числа, валюты, а также загружать переводы по demand. -
Что такое strict mode в React и зачем он нужен?
StrictMode — это инструмент для выявления потенциальных проблем в приложении. Он активирует дополнительные проверки и предупреждения в режиме разработки, такие как двойной запуск useEffect, использование устаревших методов. -
Как использовать ref в React и в чём разница между useRef и createRef?
useRef
возвращает изменяемый объект с.current
который сохраняет своё значение между рендерами.createRef
создаёт новый ref при каждом рендере.useRef
предпочтителен в функциональных компонентах. -
Что такое Lifting State Up и когда его применять?
Lifting State Up — это паттерн, при котором состояние поднимается в общего родителя, чтобы делиться им между несколькими дочерними компонентами. Применяется, когда несколько компонентов зависят от одного состояния или взаимодействуют друг с другом. -
Как обрабатывать события формы с useForm в React Hook Form?
useForm
из библиотекиreact-hook-form
предоставляет простой способ управления формами. Он регистрирует поля, валидирует значения, собирает данные и отправляет форму. Упрощает работу с контролируемыми и неконтролируемыми компонентами. -
Что такое code splitting и как он реализуется в React?
Code splitting — это разделение кода на части для уменьшения размера начальной загрузки. Реализуется черезReact.lazy()
иSuspense
либо вручную черезimport()
и Webpack-комментарии/* webpackChunkName: "my-chunk" */
-
Как использовать Web Workers в React и зачем они нужны?
Web Workers позволяют выполнять тяжелые вычисления в фоновом потоке, не блокируя основной поток. В React их можно использовать для обработки данных, шифрования, аналитики. Инициализируются черезnew Worker()
обмен данными — черезpostMessage()
иonmessage
-
Что такое reselect и как он помогает в оптимизации Redux?
Reselect — это библиотека для создания мемоизированных селекторов. Мемоизация позволяет избежать повторных вычислений, если входные данные не изменились. Это особенно полезно при работе с большими массивами или сложными преобразованиями данных. -
Как реализовать drag-and-drop в React без сторонних библиотек?
Реализация drag-and-drop возможна через нативные событияdragstart
dragover
drop
Необходимо управлять состоянием перетаскиваемого элемента и его позиции. Для более сложных сценариев рекомендуется использовать библиотеки, напримерreact-beautiful-dnd
-
Что такое Virtual DOM и как он работает?
Virtual DOM — это легковесное представление реального DOM. При изменении состояния React создает новый Virtual DOM, сравнивает его с предыдущей версией (diffing) и применяет минимальные изменения к реальному DOM для повышения производительности. -
Как работать с датами в React и какие библиотеки лучше использовать?
Для работы с датами в React используются библиотекиdate-fns
moment.js
(устаревшая),dayjs
luxon
Они предоставляют удобный API для форматирования, сравнения, вычисления разницы между датами и поддержки временных зон. -
Как организовать анимацию в React-приложениях?
Анимации можно реализовать через CSS transitions/animations, библиотекиframer-motion
react-transition-group
GSAP
Framer Motion предоставляет декларативный способ управления анимациями, включая вход/выход компонентов и жесты. -
Что такое Suspense SSR и как он влияет на рендеринг на сервере?
Suspense SSR — это механизм, который позволяет приостанавливать рендеринг части дерева компонентов до выполнения асинхронного действия. Поддерживается в Next.js 13+ и используется вместе сuse
иReact.lazy()
для серверного рендера с ожиданием данных. -
Как использовать IndexedDB в React для локального хранения данных?
IndexedDB — это клиентская база данных NoSQL, которая позволяет хранить значительные объемы структурированных данных. В React можно использовать обертки, такие какidb
или работать напрямую черезindexedDB.open()
createObjectStore
transaction
-
Что такое tree-shaking и как он работает в React?
Tree-shaking — это процесс удаления неиспользуемого кода на этапе сборки. Он работает в Webpack, Rollup и Vite при использовании ES Modules. Позволяет значительно уменьшить размер финального бандла, исключая экспорты, которые не импортируются. -
Как реализовать работу с WebSocket в React?
WebSocket поддерживает двустороннее соединение между клиентом и сервером. В React можно использовать нативныйWebSocket
либо библиотеки вродеsocket.io-client
Соединение обычно устанавливается вuseEffect
а сообщения обрабатываются черезonmessage
-
Что такое CSR и чем он отличается от SSR и SSG?
CSR (Client Side Rendering) — рендеринг происходит на клиенте после загрузки JS. SSR (Server Side Rendering) — HTML генерируется на сервере, SSG (Static Site Generation) — HTML генерируется на этапе сборки. CSR быстрее для последующих переходов, SSR и SSG лучше для SEO и первоначальной загрузки. -
Как использовать Web Components в React?
Web Components — это стандартные элементы, совместимые с любыми фреймворками. В React они используются как обычные HTML-элементы. Для передачи props и обработки событий используютсяref
addEventListener
dataset
-
Что такое микросервисная архитектура и как она связана с React?
Микросервисная архитектура предполагает разделение backend на небольшие автономные сервисы. В контексте React — это может быть микрофроненд: разделение UI на независимые части, каждая из которых развивается отдельно. Реализуется через Module Federation (Webpack 5). -
Как использовать WebAssembly в React-приложениях?
WebAssembly позволяет запускать код, написанный на других языках (Rust, C++), в браузере. В React его можно использовать для вычислений высокой интенсивности. Подключается черезfetch()
иWebAssembly.instantiate()
или через npm-пакеты, напримерwasm-bindgen
-
Как реализовать темизацию (theming) в React-приложении?
Темизация реализуется через Context API,ThemeProvider
из styled-components / Emotion, либо CSS переменные. Состояние текущей темы хранится в контексте, а компоненты получают доступ к цветам, шрифтам и другим значениям по мере необходимости. -
Что такое Module Federation и как он используется в React?
Module Federation — это функционал Webpack 5, позволяющий делиться модулями между приложениями. Используется для построения микрофронендов: один проект может динамически загружать и использовать компоненты из другого проекта без npm-зависимостей. -
Как реализовать offline-режим в React-приложении?
Offline-режим достигается через Service Workers и Cache Storage. Используются библиотеки вроде Workbox для регистрации SW и кэширования ресурсов. Также возможно использование localStorage или IndexedDB для сохранения данных пользователя. -
Что такое headless CMS и как он интегрируется с React?
Headless CMS — это система управления контентом без фронтенда. Данные предоставляются через API (REST или GraphQL). В React интеграция осуществляется через запросы к API CMS (например, Strapi, Contentful, Sanity) и отображение контента в компонентах. -
Как использовать GraphQL в React и какие библиотеки популярны?
GraphQL в React используется через Apollo Client, Relay, RTK Query или urql. Эти библиотеки позволяют отправлять запросы, кэшировать результаты, управлять состоянием и подписываться на обновления через subscriptions. -
Что такое SWR и как он помогает в управлении данными?
SWR (Stale-While-Revalidate) — это React Hooks библиотека для получения данных. Она автоматически кэширует ответы, повторно валидирует данные при фокусе на окне, повторяет запросы при ошибке и поддерживает мутации. Удобен для частых обновлений данных. -
Как реализовать пользовательскую систему плагинов в React?
Плагины можно реализовать через динамический импортimport()
контекст, публичные API, которые регистрируются в центральном хранилище. Каждый плагин предоставляет свой интерфейс, который может расширять функциональность приложения. -
Что такое barrel файлы и зачем они нужны?
Barrel файлы — это index.js/ts файлы, которые собирают и экспортируют модули из нескольких файлов. Они упрощают импорт, скрывая внутреннюю структуру директории. Например:export * from './Button'
-
Как использовать WebRTC в React для видеочата?
WebRTC позволяет организовать прямое соединение между браузерами. В React можно использовать нативныйRTCPeerConnection
либо библиотеки вродеsimple-peer
Обмен ICE-кандидатами и SDP-описаниями происходит через сигнализационный сервер. -
Что такое feature flags и как их внедрить в React?
Feature flags — это механизм условного включения/отключения функций. Реализуется через конфигурацию, переменные окружения, либо внешний сервис (например, LaunchDarkly). В React можно оборачивать компоненты в HOC или использовать контекст. -
Как реализовать CI/CD для React-проекта?
CI/CD реализуется через GitHub Actions, GitLab CI, CircleCI, Jenkins. Pipeline включает: установку зависимостей, тестирование, сборкуnpm run build
деплой на Vercel/Netlify/AWS. Также возможна проверка типов, линтинг, e2e-тесты.
-
Какой хук используется для выполнения побочных эффектов в функциональных компонентах React?
A) useEffect
B) useState
C) useReducer
D) useContext
Ответ: A -
Что возвращает метод ReactDOM.createPortal()?
A) Новый экземпляр DOM-элемента
B) Ссылку на корневой узел приложения
C) JSX, отрендеренный в указанном DOM-узле
D) Объект portal, который можно включать в JSX
Ответ: D -
Какое значение по умолчанию возвращает createContext()?
A) null
B) undefined
C) Пустой объект {}
D) Значение не задано
Ответ: B -
Что делает функция React.memo()?
A) Оптимизирует рендеринг списка элементов
B) Предотвращает повторный рендер компонента при изменении состояния
C) Кэширует результат вычисления сложных функций
D) Выполняет мемоизацию компонента по его props
Ответ: D -
Какой тип ключа лучше всего использовать для элементов списка в React?
A) Индекс элемента
B) Уникальное строковое значение (например, UUID)
C) Числовой идентификатор из БД
D) Любое значение, главное — уникальность
Ответ: B -
Что произойдет, если вызвать setState с тем же значением, что и текущее состояние?
A) Компонент перерендерится
B) React проигнорирует обновление
C) Вызовет ошибку
D) Перезагрузит страницу
Ответ: B -
Как реализовать ленивую загрузку компонента в React?
A) Использовать React.lazy() и Suspense
B) Использовать import() внутри useEffect
C) Применить асинхронный render в родительском компоненте
D) Ленивая загрузка невозможна без Redux
Ответ: A -
Что такое reconciliation в контексте React?
A) Процесс сравнения DOM-дерева перед и после обновления
B) Процесс создания нового Virtual DOM
C) Процесс объединения стейта
D) Процесс оптимизации props
Ответ: A -
Как получить доступ к DOM-элементу в React?
A) Через useRef()
B) Через state
C) Через props
D) Через context
Ответ: A -
Что возвращает хук useReducer()?
A) Массив из текущего состояния и диспетчера
B) Текущее состояние и функцию для его обновления
C) Функцию dispatch и новое состояние
D) Только текущее состояние
Ответ: A -
Какие данные должны быть в состоянии (state), а не в переменной?
A) Данные, которые никогда не изменяются
B) Данные, влияющие на UI
C) Данные, используемые только в одном компоненте
D) Данные, полученные из API один раз
Ответ: B -
Что такое Error Boundary в React?
A) Компонент, который ловит ошибки рендера
B) Встроенный обработчик исключений JavaScript
C) Хук, отлавливающий ошибки
D) Метод жизненного цикла классового компонента
Ответ: A -
Какой тип данных нельзя передавать через Context в React?
A) Объект
B) Функция
C) Примитив
D) Все варианты допустимы
Ответ: D -
Что происходит при вызове setState в componentWillUnmount()?
A) Состояние обновляется, но компонент уже не отрендерен
B) React выбросит ошибку
C) Состояние не обновляется
D) React предупредит о возможной утечке памяти
Ответ: C -
Какой метод жизненного цикла вызывается сразу после монтирования компонента?
A) componentWillMount()
B) componentDidMount()
C) render()
D) shouldComponentUpdate()
Ответ: B -
Что делает оператор spread в JSX?
A) Передает пропсы как объект
B) Распаковывает массив в элементы
C) Вызывает функцию
D) Ничего, он не работает в JSX
Ответ: A -
Как проверить тип props в React?
A) PropTypes
B) TypeScript
C) Flow
D) Все вышеперечисленные
Ответ: D -
Что возвращает React.Fragment?
A) Обычный div
B) Виртуальный узел без DOM-представления
C) Корневой элемент
D) Компонент, оборачивающий всё приложение
Ответ: B -
Какой хук используется для получения ссылки на дочерний компонент?
A) useRef()
B) forwardRef()
C) createRef()
D) useImperativeHandle()
Ответ: D -
Что делает React.PureComponent?
A) Автоматически выполняет мемоизацию
B) Реализует shouldComponentUpdate() поверхностного сравнения
C) Не имеет методов жизненного цикла
D) Оптимизирует работу с контекстом
Ответ: B -
Какой тип обновления состояния гарантирует актуальное значение state?
A) Передача нового значения напрямую
B) Передача функции в setState
C) Использование async/await
D) Использование useEffect
Ответ: B -
Что такое Portals в React?
A) Механизм для работы с DOM вне дерева компонентов
B) Рендеринг в iframe
C) Специальная конструкция для условного рендера
D) Подключение внешних библиотек
Ответ: A -
Как обновить состояние на основе предыдущего значения с помощью useState()?
A) Передать новое значение напрямую
B) Передать функцию, принимающую prevValue
C) Использовать useEffect
D) Использовать useReducer
Ответ: B -
Какой метод жизненного цикла позволяет предотвратить ненужный рендер?
A) componentWillReceiveProps()
B) shouldComponentUpdate()
C) componentDidUpdate()
D) UNSAFE_componentWillUpdate()
Ответ: B -
Какой из следующих подходов считается лучшей практикой для обработки форм в React?
A) Использовать uncontrolled components
B) Использовать controlled components
C) Использовать localStorage для хранения состояния формы
D) Использовать Redux Form
Ответ: B
-
Какой хук используется для мемоизации функций в React?
A) useMemo()
B) useCallback()
C) useEffect()
D) useReducer()
Ответ: B -
Что такое reconciliation algorithm в React и как он работает?
A) Алгоритм сравнения DOM-деревьев на основе индексов и ключей
B) Алгоритм управления состоянием приложения
C) Механизм оптимизации рендера через PureComponent
D) Система обработки событий в React
Ответ: A -
Как правильно обновить вложенный объект в состоянии с помощью useState()?
A) setObj({...obj, key: newValue})
B) setObj(prev => ({...prev, key: newValue}))
C) setObj({...obj.key, newValue})
D) obj.key = newValue
Ответ: B -
Что делает метод ReactDOM.render()?
A) Создаёт новый Virtual DOM
B) Обновляет существующий корневой узел
C) Монтирует React-компонент в указанный DOM-узел
D) Уничтожает текущее приложение
Ответ: C -
Какой тип контекста лучше использовать для глобального состояния?
A) Local state
B) Redux store
C) React Context API
D) SessionStorage
Ответ: C -
Что означает термин «lifting state up» в React?
A) Перенос состояния из дочерних компонентов в родительский
B) Хранение состояния в localStorage
C) Передача состояния через props
D) Использование useContext вместо Redux
Ответ: A -
Как реализовать серверный рендеринг (SSR) в React-приложении?
A) Через ReactDOM.renderToString()
B) Через ReactDOM.createPortal()
C) Через React.lazy()
D) Через React.PureComponent
Ответ: A -
Что происходит при вызове setState после unmount компонента?
A) Состояние успешно обновляется
B) Выбрасывается исключение
C) Обновление игнорируется
D) Происходит утечка памяти
Ответ: D -
Какой хук используется для получения предыдущего значения пропсов или состояния?
A) useRef()
B) useState()
C) useEffect()
D) usePrevious() (пользовательский хук)
Ответ: D -
Что такое controlled component в React?
A) Компонент, который получает значение из state и обновляет его через handleChange
B) Компонент, использующий defaultValue
C) Компонент, управляющий формами через DOM
D) Компонент, использующий localStorage для хранения данных
Ответ: A -
Как получить доступ к props в статическом методе getDerivedStateFromProps()?
A) Никак, props недоступны
B) Из аргумента метода
C) Из this.props
D) Из контекста
Ответ: B -
Что возвращает метод render() классового компонента?
A) JSX
B) JSX или null
C) Текстовое значение
D) Объект Virtual DOM
Ответ: B -
Какое значение передается первым аргументом в reducer-функцию при использовании useReducer()?
A) Текущее состояние
B) Действие (action)
C) Предыдущее состояние
D) Новое состояние
Ответ: A -
Что такое Higher-Order Component (HOC)?
A) Функция, которая принимает компонент и возвращает новый компонент
B) Классовый компонент с расширенным функционалом
C) Компонент, принимающий children
D) Функция, возвращающая JSX
Ответ: A -
Какой тип обновления состояния не гарантирует актуальное значение props/state внутри эффекта?
A) Асинхронные колбэки в useEffect
B) Передача функции в setState
C) Использование useReducer
D) Прямая передача нового значения
Ответ: A -
Что делает свойство key в списке элементов?
A) Определяет порядок рендера
B) Помогает React эффективно обновлять список
C) Задаёт уникальное имя компонента
D) Не влияет на производительность
Ответ: B -
Как использовать Suspense для ленивой загрузки компонента?
A) Обернуть React.lazy() в тег <Suspense>
B) Вызвать import() внутри useEffect
C) Использовать await внутри render
D) Ленивая загрузка без Suspense невозможна
Ответ: A -
Что делает хук useLayoutEffect()?
A) Выполняет побочные эффекты до рендера
B) Выполняет побочные эффекты после рендера, но до отрисовки браузера
C) Выполняет эффект только один раз
D) Аналогичен useEffect(), но запускается раньше
Ответ: B -
Какой подход считается наиболее предпочтительным для работы с HTTP-запросами в React?
A) useEffect() + fetch()
B) componentDidMount() + XMLHttpRequest
C) componentWillReceiveProps() + fetch
D) Все варианты допустимы
Ответ: A -
Что представляет собой Virtual DOM в React?
A) Точную копию реального DOM
B) Легковесное представление DOM для сравнения изменений
C) Объект, создаваемый ReactDOM
D) Встроенный механизм браузера
Ответ: B -
Что происходит при повторном рендере компонента с одинаковым значением props?
A) React всегда перерендеривает
B) React может пропустить рендер при использовании React.memo()
C) React генерирует ошибку
D) React перезагружает страницу
Ответ: B -
Какой хук позволяет сохранять значение между рендерами без вызова эффекта?
A) useState()
B) useRef()
C) useMemo()
D) useCallback()
Ответ: B -
Что такое reconciliation key в React?
A) Уникальный идентификатор элемента
B) Специальный prop, помогающий React отличать элементы друг от друга
C) Ключ контекста
D) Индекс массива
Ответ: B -
Какой из следующих способов рекомендуется использовать для оптимизации рендеринга списка?
A) React.memo() для каждого элемента
B) Использование индекса как key
C) Использование useMemo() для всего списка
D) PureComponent для родителя
Ответ: A -
Что означает термин «reconciliation» в React?
A) Сравнение Virtual DOM с реальным перед обновлением
B) Сравнение props и state
C) Сравнение контекстов
D) Сравнение двух деревьев компонентов
Ответ: A
-
Какой хук используется для создания пользовательских хуков в React?
A) useEffect()
B) useState()
C) useCustomHook()
D) Нет специального хука, пользовательские хуки создаются как обычные функции
Ответ: D -
Что такое reconciliation и как он влияет на производительность?
A) Это процесс сравнения Virtual DOM перед обновлением — может улучшать производительность
B) Это процесс монтирования компонентов — не влияет на производительность
C) Это процесс обработки событий — ухудшает производительность
D) Это процесс рендеринга JSX — не влияет на производительность
Ответ: A -
Как правильно использовать асинхронные эффекты внутри useEffect()?
A) Оборачивать в async/await напрямую
B) Создавать асинхронную IIFE внутри useEffect()
C) Использовать только синхронные эффекты
D) Асинхронные эффекты запрещены в useEffect()
Ответ: B -
Какое из следующих утверждений о PureComponent неверно?
A) Реализует shouldComponentUpdate() с поверхностным сравнением props и state
B) Рекомендуется использовать вместо Component для оптимизации
C) Подходит для глубоких объектов без дополнительной логики
D) Уменьшает количество ненужных перерисовок
Ответ: C -
Что делает метод getSnapshotBeforeUpdate() в классовых компонентах?
A) Возвращает значение, доступное в componentDidUpdate() до обновления DOM
B) Возвращает значение после обновления DOM
C) Выполняет побочный эффект до unmount
D) Используется для работы с контекстом
Ответ: A -
Как реализовать кастомный хук для получения размеров окна браузера?
A) С использованием useEffect(), window.addEventListener и useState()
B) Через componentDidMount() и window.resize
C) Только через внешние библиотеки
D) С помощью useRef() и window.onresize
Ответ: A -
Что происходит при вызове setState в асинхронном колбэке вне зоны React?
A) React не отслеживает изменения
B) React автоматически триггерит перерисовку
C) Происходит ошибка выполнения
D) React предупреждает, но продолжает работу
Ответ: A -
Какой тип данных лучше всего подходит для использования в качестве ключей (key) в списках?
A) Индекс массива
B) Случайная строка
C) Уникальный идентификатор из БД
D) Число, полученное из Date.now()
Ответ: C -
Что представляет собой термин «controlled component» в React?
A) Компонент, управляющий состоянием формы через DOM API
B) Компонент, использующий defaultValue и innerHTML
C) Компонент, который получает значение из state и управляет им через handleChange
D) Компонент, использующий localStorage для хранения формы
Ответ: C -
Как реализовать глобальное состояние в React без Redux?
A) Использовать React Context API + useReducer
B) Использовать только useState в корневом компоненте
C) Хранить всё в localStorage
D) Глобальное состояние невозможно создать без Redux
Ответ: A -
Что возвращает хук useMemo()?
A) Значение, вычисленное мемоизированным образом
B) Функцию, которая будет вызвана позже
C) Состояние, которое не изменяется
D) Пропсы, прошедшие проверку
Ответ: A -
Какое утверждение о работе Virtual DOM верно?
A) React всегда полностью пересоздаёт DOM
B) React работает напрямую с реальным DOM
C) React сравнивает Virtual DOM с реальным и применяет минимальные изменения
D) Virtual DOM заменяет собой реальный DOM
Ответ: C -
Как получить доступ к ref дочернего элемента в функциональном компоненте?
A) Использовать forwardRef и useImperativeHandle
B) Передать ref через props
C) Использовать createRef() внутри дочернего компонента
D) Ref нельзя передавать
Ответ: A -
Какой из следующих способов является наиболее эффективным для оптимизации рендера списка?
A) Использование индекса как key
B) Использование React.memo() для каждого элемента
C) Использование PureComponent для родителя
D) Все варианты одинаково эффективны
Ответ: B -
Что произойдет, если передать в React.createContext() значение, которое затем изменится?
A) Все потребители контекста получат новое значение
B) Контекст не обновится без Provider
C) Приложение перезапустится
D) Изменения будут игнорироваться
Ответ: B -
Какой из следующих подходов считается лучшей практикой для работы с формами в React?
A) Uncontrolled components
B) Controlled components
C) Использование localStorage для хранения состояния
D) Использование Redux Form
Ответ: B -
Что делает Suspense в React?
A) Откладывает рендеринг дочерних компонентов до загрузки асинхронного кода
B) Отображает спиннер при ошибке
C) Ускоряет рендеринг приложения
D) Не влияет на поведение приложения
Ответ: A -
Какой из следующих хуков позволяет сохранять ссылку на значение между рендерами, не вызывая повторного рендера?
A) useState()
B) useCallback()
C) useRef()
D) useMemo()
Ответ: C -
Какой из следующих паттернов используется для разделения UI на независимые, повторно используемые части?
A) HOC
B) Render Props
C) Component Composition
D) Все вышеперечисленные
Ответ: D -
Что такое reconciliation algorithm в React и как он влияет на производительность?
A) Алгоритм, который минимизирует обновления DOM за счет сравнения Virtual DOM
B) Алгоритм, который увеличивает нагрузку на браузер
C) Алгоритм, который не влияет на производительность
D) Алгоритм, который перерисовывает весь DOM при каждом изменении
Ответ: A -
Какой из следующих подходов позволяет уменьшить количество повторных рендеров компонентов?
A) React.memo()
B) useEffect()
C) useContext()
D) useLayoutEffect()
Ответ: A -
Что возвращает ReactDOM.hydrate()?
A) Тот же результат, что и ReactDOM.render(), но для SSR
B) Рендеринг на сервере
C) Отрисовка HTML-страницы
D) Очистка DOM
Ответ: A -
Какой из следующих хуков следует использовать для выполнения эффектов, зависящих от layout?
A) useEffect()
B) useLayoutEffect()
C) useMemo()
D) useCallback()
Ответ: B -
Что происходит при использовании useEffect() без зависимостей?
A) Эффект выполняется при каждом рендере
B) Эффект выполняется только при монтировании
C) Эффект не выполняется никогда
D) Эффект выполняется при размонтировании
Ответ: A -
Какое утверждение о работе React.StrictMode неверно?
A) Он активирует дополнительные проверки и предупреждения
B) Он вызывает двойной рендер в режиме разработки
C) Он влияет на поведение приложения в продакшене
D) Он помогает находить потенциальные проблемы
Ответ: C
Экзаменационный билет №1
Теоретическая часть
-
Объясните, в чём заключается разница между
useEffect
иuseLayoutEffect
Приведите примеры ситуаций, когда следует использовать каждый из них. -
Что такое reconciliation в React и как он влияет на производительность рендеринга? Опишите принцип работы алгоритма согласования.
Ответы на теоретическую часть:
useEffect
запускается асинхронно после завершения рендера и отрисовки компонента в браузере — это стандартное поведение для большинства побочных эффектов (например, подписки, API-запросы).useLayoutEffect
запускается синхронно сразу после рендера, но до того, как браузер перерисует экран — используется, если нужно прочитать макет или размеры DOM перед отображением (например, позиционирование попапа).- Reconciliation — это процесс сравнения нового Virtual DOM с предыдущим, чтобы определить минимальные изменения для обновления реального DOM. Это позволяет React работать эффективно, минимизируя дорогостоящие операции. Алгоритм использует стратегию сравнения по типу элементов и ключам
key
что особенно важно при работе со списками.
Практическая часть
Реализуйте пользовательский хук useLocalStorage
который принимает ключ и начальное значение, и возвращает массив [value, setValue, clearValue]
Значение должно сохраняться в localStorage
и восстанавливаться при повторном монтировании. Также реализуйте функцию clearValue
которая удаляет запись из localStorage
и сбрасывает значение к начальному.
const useLocalStorage = (key, initialValue) => {
const [value, setValue] = useState(() => {
try {
const storedValue = localStorage.getItem(key);
return storedValue !== null ? JSON.parse(storedValue) : initialValue;
} catch (error) {
return initialValue;
}
});
useEffect(() => {
localStorage.setItem(key, JSON.stringify(value));
}, [key, value]);
const clearValue = () => {
localStorage.removeItem(key);
setValue(initialValue);
};
return [value, setValue, clearValue];
};
Экзаменационный билет №2
Теоретическая часть
-
Что такое «controlled components» и зачем они используются в React? Объясните, почему их предпочтительно использовать вместо uncontrolled компонентов.
-
Охарактеризуйте механизм работы
React.memo()
иuseMemo()
В чём разница между ними и в каких случаях следует использовать каждый из них?
Ответы на теоретическую часть:
- Controlled components — это элементы формы например,
<input>
<select>
состояние которых управляется черезstate
в React-компоненте. Это позволяет централизованно контролировать данные, обрабатывать изменения и валидацию, а также синхронизировать состояние формы с другими частями приложения. Такой подход обеспечивает однонаправленный поток данных и делает форму более предсказуемой и управляемой по сравнению с uncontrolled компонентами, которые полагаются на DOM для хранения состояния. React.memo()
— это Higher-Order Component, используемый для оптимизации рендеринга дочерних компонентов. Он предотвращает повторный рендер компонента, если его props не изменились. Применяется для компонентов, которые часто получают одни и те же props и дорогостоящие перерисовки.
Практическая часть
Реализуйте компонент AutoSuggestInput
принимающий список строкoptions
и функцию onSelect
Компонент должен отображать текстовое поле и выпадающий список совпадений по мере ввода. При выборе варианта из списка вызывается onSelect
а введённое значение должно обновляться. Поиск должен быть регистронезависимым. Добавьте возможность фильтрации только тех вариантов, которые содержат введённую подстроку.
const AutoSuggestInput = ({ options, onSelect }) => {
const [query, setQuery] = useState('');
const [isOpen, setIsOpen] = useState(false);
const filteredOptions = useMemo(() => {
if (!query) return options;
const lowerQuery = query.toLowerCase();
return options.filter(option =>
option.toLowerCase().includes(lowerQuery)
);
}, [options, query]);
const handleSelect = (option) => {
setQuery(option);
setIsOpen(false);
onSelect(option);
};
return (
<div style={{ position: 'relative' }}>
<input
type="text"
value={query}
onChange={(e) => setQuery(e.target.value)}
onFocus={() => setIsOpen(true)}
placeholder="Введите запрос"
/>
{isOpen && filteredOptions.length > 0 && (
<ul style={{
position: 'absolute',
top: '100%',
left: 0,
right: 0,
maxHeight: '200px',
overflowY: 'auto',
border: '1px solid #ccc',
backgroundColor: '#fff',
zIndex: 1000,
listStyle: 'none',
margin: 0,
padding: 0
}}>
{filteredOptions.map((option, index) => (
<li
key={index}
onClick={() => handleSelect(option)}
style={{ padding: '8px', cursor: 'pointer' }}
onMouseEnter={(e) => e.currentTarget.style.backgroundColor = '#f0f0f0'}
onMouseLeave={(e) => e.currentTarget.style.backgroundColor = 'transparent'}
>
{option}
</li>
))}
</ul>
)}
</div>
);
};
Экзаменационный билет №3
Теоретическая часть
-
Объясните, что такое Virtual DOM и как он помогает в повышении производительности React-приложений.
-
Что такое Higher-Order Component (HOC)? Приведите пример использования и укажите его основные преимущества и недостатки.
Ответы на теоретическую часть:
- Virtual DOM — это легковесное представление реального DOM, используемое React для эффективного обновления интерфейса. При изменении состояния React создаёт новый Virtual DOM, сравнивает его со старым (reconciliation), вычисляет минимальные изменения и применяет их к реальному DOM. Это позволяет избежать частых и дорогостоящих операций обновления DOM напрямую, тем самым повышая производительность приложения.
- Higher-Order Component (HOC) — это функция, которая принимает компонент и возвращает новый компонент с дополнительным поведением или props. Используется для повторного использования логики между компонентами (например, авторизация, загрузка данных).
Практическая часть
Реализуйте пользовательский хук useDebounce
который принимает значение и задержку, и возвращает это значение с задержкой обновления. Хук должен быть полезен при реализации поиска с debounce, чтобы не отправлять запросы слишком часто.
const useDebounce = (value, delay) => {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const handler = setTimeout(() => {
setDebouncedValue(value);
}, delay);
return () => {
clearTimeout(handler);
};
}, [value, delay]);
return debouncedValue;
};
Экзаменационный билет №4
Теоретическая часть
-
Что такое «uncontrolled components» в React? В каких случаях их использование оправдано и какие инструменты предоставляет React для работы с ними?
-
Объясните, что такое Portals в React и приведите примеры использования.
Ответы на теоретическую часть:
- Uncontrolled components — это элементы формы например,
<input>
<textarea>
<select>
состояние которых управляется напрямую DOM-элементом, а не React. Для доступа к их значению используетсяref
Такие компоненты полезны при простых формах или интеграции с не-React библиотеками, где нет необходимости синхронизировать состояние в React. - Portals в React позволяют рендерить дочерние элементы вне иерархии родительского компонента в произвольном DOM-узле. Это особенно полезно для модальных окон, тултипов, уведомлений и других UI-компонентов, которые должны отображаться поверх основного контента без влияния на структуру CSS-позиционирования.
Практическая часть
Реализуйте функциональный компонент ModalWindow
который принимает children
и onClose
Модальное окно должно появляться при нажатии на кнопку "Открыть", затем отображать содержимое и закрываться по клику на фон или кнопку "Закрыть". Используйте портал для вывода окна в корневой элемент #modal-root
const ModalWindow = ({ children, onClose }) => {
const modalRoot = document.getElementById('modal-root');
useEffect(() => {
const handleEscape = (e) => {
if (e.key === 'Escape') onClose();
};
window.addEventListener('keydown', handleEscape);
return () => window.removeEventListener('keydown', handleEscape);
}, [onClose]);
const handleOverlayClick = (e) => {
if (e.target === e.currentTarget) onClose();
};
const modalContent = (
<div className="modal-overlay" onClick={handleOverlayClick}>
<div className="modal-content">
<button className="close-button" onClick={onClose}>×</button>
{children}
</div>
</div>
);
return ReactDOM.createPortal(modalContent, modalRoot);
};
// Пример использования:
function App() {
const [isModalOpen, setIsModalOpen] = useState(false);
return (
<div>
<button onClick={() => setIsModalOpen(true)}>Открыть модальное окно</button>
{isModalOpen && (
<ModalWindow onClose={() => setIsModalOpen(false)}>
<h2>Модальное окно</h2>
<p>Это содержимое модального окна.</p>
</ModalWindow>
)}
</div>
);
}
Экзаменационный билет №5
Теоретическая часть
-
Что такое React Context API и в каких случаях она применяется? Какие основные компоненты предоставляет Context API?
-
Охарактеризуйте работу хука
useReducer
В чём его преимущество передuseState
и когда он наиболее уместен?
Ответы на теоретическую часть:
- React Context API — это механизм передачи данных через дерево компонентов без необходимости явно передавать props на каждом уровне. Чаще всего используется для передачи глобального состояния, такого как тема приложения, данные авторизации, языковые настройки и т. д.
- Хук
useReducer
используется для управления сложным состоянием, особенно если оно содержит несколько подзначений или если следующее состояние зависит от предыдущего. Он похож на Redux: принимает редюсер (функцию, которая возвращает новое состояние на основе действия) и начальное состояние.
Практическая часть
Реализуйте простую форму входа с помощью useReducer
где состояние включает email
password
isLoading
error
Добавьте валидацию email и возможность отправки формы. Форма должна иметь кнопку "Войти" и отображать ошибку, если ввод некорректный или запрос не удался.
const formReducer = (state, action) => {
switch (action.type) {
case 'change_email':
return { ...state, email: action.payload, error: '' };
case 'change_password':
return { ...state, password: action.payload, error: '' };
case 'submit_start':
return { ...state, isLoading: true, error: '' };
case 'submit_success':
return { ...state, isLoading: false };
case 'submit_error':
return { ...state, isLoading: false, error: action.payload };
case 'validate_email':
return { ...state, error: 'Введите корректный email' };
default:
return state;
}
};
const LoginForm = () => {
const [state, dispatch] = useReducer(formReducer, {
email: '',
password: '',
isLoading: false,
error: ''
});
const handleSubmit = (e) => {
e.preventDefault();
const isValidEmail = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(state.email);
if (!isValidEmail) {
dispatch({ type: 'validate_email' });
return;
}
dispatch({ type: 'submit_start' });
// Мокаем асинхронный запрос
setTimeout(() => {
if (state.password.length < 6) {
dispatch({ type: 'submit_error', payload: 'Неверный пароль' });
} else {
dispatch({ type: 'submit_success' });
alert('Вход выполнен успешно');
}
}, 1000);
};
return (
<form onSubmit={handleSubmit} style={{ maxWidth: '300px', margin: 'auto' }}>
<h2>Вход</h2>
{state.error && <div style={{ color: 'red' }}>{state.error}</div>}
<div>
<label>Email:</label>
<input
type="text"
value={state.email}
onChange={(e) => dispatch({ type: 'change_email', payload: e.target.value })}
/>
</div>
<div>
<label>Пароль:</label>
<input
type="password"
value={state.password}
onChange={(e) => dispatch({ type: 'change_password', payload: e.target.value })}
/>
</div>
<button type="submit" disabled={state.isLoading}>
{state.isLoading ? 'Загрузка...' : 'Войти'}
</button>
</form>
);
};
Экзаменационный билет №6
Теоретическая часть
-
Охарактеризуйте, как работает механизм reconciliation в React и какие стратегии используются для повышения его эффективности.
-
Что такое пользовательские хуки (custom hooks) и какие правила их создания и использования в React?
Ответы на теоретическую часть:
- Reconciliation — это процесс сравнения нового Virtual DOM с предыдущим, чтобы определить минимальные изменения для обновления реального DOM. Это позволяет React работать максимально производительно, избегая полной перерисовки интерфейса.
- Пользовательские хуки — это функции, начинающиеся с префикса
use
которые могут использовать встроенные хуки ReactuseState
useEffect
useContext
и др. для реализации повторно используемой логики между компонентами. Они не создают собственного контекста рендера, а просто абстрагируют состояние и побочные эффекты.
Практическая часть
Реализуйте пользовательский хук useFetch
который принимает URL и параметры запроса, и возвращает объект { data, loading, error }
Хук должен выполнять fetch-запрос, обрабатывать ошибки и поддерживать отмену запроса при размонтировании компонента.
const useFetch = (url, options = {}) => {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
let isMounted = true;
const abortController = new AbortController();
const fetchData = async () => {
try {
const response = await fetch(url, {
...options,
signal: abortController.signal
});
if (!response.ok) throw new Error(`Ошибка HTTP: ${response.status}`);
const result = await response.json();
if (isMounted) {
setData(result);
setLoading(false);
}
} catch (err) {
if (isMounted && err.name !== 'AbortError') {
setError(err.message);
setLoading(false);
}
}
};
fetchData();
return () => {
isMounted = false;
abortController.abort();
};
}, [url, options]);
return { data, loading, error };
};
Экзаменационный билет №7
Теоретическая часть
-
Объясните, что такое PureComponent и React.memo. В чём их отличие и когда следует использовать каждый из них?
-
Что такое порталы в React и зачем они нужны? Приведите примеры использования.
Ответы на теоретическую часть:
-
PureComponent — это базовый класс для классовых компонентов, реализующий метод
shouldComponentUpdate()
с поверхностным сравнением props и state. Он предотвращает ненужный рендер, если данные не изменились.React.memo
— это Higher-Order Component, который применяется к функциональным компонентам и делает то же самое — сравнивает props и пропускает рендер, если они не изменились.Разница:
PureComponent
работает с классовыми компонентами.React.memo
— с функциональными.React.memo
можно расширить, передав свою функцию сравнения вторым аргументом.
Используется, когда нужно оптимизировать рендеринг часто используемых компонентов, особенно в списках или табличных данных.
- Portals в React позволяют рендерить дочерние элементы вне иерархии родительского компонента в произвольном DOM-узле. Это особенно полезно для модальных окон, уведомлений, тултипов и других UI-компонентов, которые должны быть позиционированы вне текущего контекста CSS.
Практическая часть
Создайте компонент TabPanel
принимающий массив вкладок tabs
и отображающий содержимое активной вкладки. Каждая вкладка должна иметь заголовок и содержимое. При клике на вкладку должно меняться состояние активной вкладки. Добавьте возможность отключения вкладок и стилизовать активную вкладку.
const TabPanel = ({ tabs }) => {
const [activeIndex, setActiveIndex] = useState(0);
const handleTabClick = (index) => {
if (!tabs[index].disabled) {
setActiveIndex(index);
}
};
return (
<div className="tab-panel">
<div className="tab-list" role="tablist">
{tabs.map((tab, index) => (
<button
key={index}
role="tab"
aria-selected={index === activeIndex}
disabled={tab.disabled}
onClick={() => handleTabClick(index)}
className={`tab-button ${index === activeIndex ? 'active' : ''}`}
>
{tab.title}
</button>
))}
</div>
<div className="tab-content" role="tabpanel">
{tabs[activeIndex].content}
</div>
</div>
);
};
// Пример использования:
function App() {
const tabs = [
{
title: 'Вкладка 1',
content: <p>Содержимое первой вкладки.</p>,
disabled: false
},
{
title: 'Вкладка 2',
content: <p>Содержимое второй вкладки.</p>,
disabled: false
},
{
title: 'Заблокировано',
content: <p>Эта вкладка отключена.</p>,
disabled: true
}
];
return <TabPanel tabs={tabs} />;
}
Экзаменационный билет №8
Теоретическая часть
-
Объясните, в чём заключается разница между
useEffect
иuseLayoutEffect
Приведите примеры ситуаций, когда следует использовать каждый из них. -
Что такое «controlled components» и зачем они используются в React? Объясните, почему их предпочтительно использовать вместо uncontrolled компонентов.
Ответы на теоретическую часть:
-
useEffect запускается асинхронно после завершения рендера и отрисовки компонента в браузере — это стандартное поведение для большинства побочных эффектов (например, подписки, API-запросы).
useLayoutEffect
запускается синхронно сразу после рендера, но до того, как браузер перерисует экран — используется, если нужно прочитать макет или размеры DOM перед отображением (например, позиционирование попапа, обновление стилей динамически).Используйте
useLayoutEffect
если вам нужно выполнить изменения, которые влияют на визуальное представление элемента до его отрисовки. - Controlled components — это элементы формы например,
<input>
<select>
состояние которых управляется черезstate
в React-компоненте. Это позволяет централизованно контролировать данные, обрабатывать изменения и валидацию, а также синхронизировать состояние формы с другими частями приложения.
Практическая часть
Реализуйте пользовательский хук useDebounce
который принимает значение и задержку, и возвращает это значение с задержкой обновления. Хук должен быть полезен при реализации поиска с debounce, чтобы не отправлять запросы слишком часто.
const useDebounce = (value, delay) => {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const handler = setTimeout(() => {
setDebouncedValue(value);
}, delay);
return () => {
clearTimeout(handler);
};
}, [value, delay]);
return debouncedValue;
};
Экзаменационный билет №9
Теоретическая часть
-
Что такое Virtual DOM и как он помогает в повышении производительности React-приложений?
-
Что такое Higher-Order Component (HOC)? Приведите пример использования и укажите его основные преимущества и недостатки.
Ответы на теоретическую часть:
- Virtual DOM — это легковесное представление реального DOM, используемое React для эффективного обновления интерфейса. При изменении состояния React создаёт новый Virtual DOM, сравнивает его со старым (reconciliation), вычисляет минимальные изменения и применяет их к реальному DOM. Это позволяет избежать частых и дорогостоящих операций обновления DOM напрямую, тем самым повышая производительность приложения.
- Higher-Order Component (HOC) — это функция, которая принимает компонент и возвращает новый компонент с дополнительным поведением или props. Используется для повторного использования логики между компонентами (например, авторизация, загрузка данных).
Практическая часть
Реализуйте компонент AutoSuggestInput
принимающий список строкoptions
и функцию onSelect
Компонент должен отображать текстовое поле и выпадающий список совпадений по мере ввода. При выборе варианта из списка вызывается onSelect
а введённое значение должно обновляться. Поиск должен быть регистронезависимым. Добавьте возможность фильтрации только тех вариантов, которые содержат введённую подстроку.
const AutoSuggestInput = ({ options, onSelect }) => {
const [query, setQuery] = useState('');
const [isOpen, setIsOpen] = useState(false);
const filteredOptions = useMemo(() => {
if (!query) return options;
const lowerQuery = query.toLowerCase();
return options.filter(option =>
option.toLowerCase().includes(lowerQuery)
);
}, [options, query]);
const handleSelect = (option) => {
setQuery(option);
setIsOpen(false);
onSelect(option);
};
return (
<div style={{ position: 'relative' }}>
<input
type="text"
value={query}
onChange={(e) => setQuery(e.target.value)}
onFocus={() => setIsOpen(true)}
placeholder="Введите запрос"
/>
{isOpen && filteredOptions.length > 0 && (
<ul style={{
position: 'absolute',
top: '100%',
left: 0,
right: 0,
maxHeight: '200px',
overflowY: 'auto',
border: '1px solid #ccc',
backgroundColor: '#fff',
zIndex: 1000,
listStyle: 'none',
margin: 0,
padding: 0
}}>
{filteredOptions.map((option, index) => (
<li
key={index}
onClick={() => handleSelect(option)}
style={{ padding: '8px', cursor: 'pointer' }}
onMouseEnter={(e) => e.currentTarget.style.backgroundColor = '#f0f0f0'}
onMouseLeave={(e) => e.currentTarget.style.backgroundColor = 'transparent'}
>
{option}
</li>
))}
</ul>
)}
</div>
);
};
Экзаменационный билет №10
Теоретическая часть
-
Что такое reconciliation и как он влияет на производительность рендеринга? Опишите принцип работы алгоритма согласования.
-
Что такое React Context API и в каких случаях она применяется? Какие основные компоненты предоставляет Context API?
Ответы на теоретическую часть:
- Reconciliation — это процесс сравнения нового Virtual DOM с предыдущим, чтобы определить минимальные изменения для обновления реального DOM. Это позволяет React работать максимально производительно, избегая полной перерисовки интерфейса. Алгоритм использует два ключевых подхода:
- Сравнение по типу элемента: если типы элементов разные — узел полностью заменяется.
- Использование
key
для корректного сравнения элементов списка, что помогает React точно определить, какие элементы были изменены, добавлены или удалены.
- React Context API — это механизм передачи данных через дерево компонентов без необходимости явно передавать props на каждом уровне. Чаще всего используется для передачи глобального состояния, такого как тема приложения, данные авторизации, языковые настройки и т. д.
Практическая часть
Реализуйте пользовательский хук useLocalStorage
который принимает ключ и начальное значение, и возвращает массив [value, setValue, clearValue]
Значение должно сохраняться в localStorage
и восстанавливаться при повторном монтировании. Также реализуйте функцию clearValue
которая удаляет запись из localStorage
и сбрасывает значение к начальному.
const useLocalStorage = (key, initialValue) => {
const [value, setValue] = useState(() => {
try {
const storedValue = localStorage.getItem(key);
return storedValue !== null ? JSON.parse(storedValue) : initialValue;
} catch (error) {
return initialValue;
}
});
useEffect(() => {
localStorage.setItem(key, JSON.stringify(value));
}, [key, value]);
const clearValue = () => {
localStorage.removeItem(key);
setValue(initialValue);
};
return [value, setValue, clearValue];
};
Экзаменационный билет №11
Теоретическая часть
-
Что такое «uncontrolled components» в React? В каких случаях их использование оправдано и какие инструменты предоставляет React для работы с ними?
-
Объясните, что такое Portals в React и приведите примеры использования.
Ответы на теоретическую часть:
- Uncontrolled components — это элементы формы например,
<input>
<textarea>
<select>
состояние которых управляется напрямую DOM-элементом, а не React. Для доступа к их значению используетсяref
Такие компоненты полезны при простых формах или интеграции с не-React библиотеками, где нет необходимости синхронизировать состояние в React. - Portals в React позволяют рендерить дочерние элементы вне иерархии родительского компонента в произвольном DOM-узле. Это особенно полезно для модальных окон, тултипов, уведомлений и других UI-компонентов, которые должны отображаться поверх основного контента без влияния на структуру CSS-позиционирования.
Практическая часть
Реализуйте функциональный компонент ModalWindow
который принимает children
и onClose
Модальное окно должно появляться при нажатии на кнопку "Открыть", затем отображать содержимое и закрываться по клику на фон или кнопку "Закрыть". Используйте портал для вывода окна в корневой элемент #modal-root
const ModalWindow = ({ children, onClose }) => {
const modalRoot = document.getElementById('modal-root');
useEffect(() => {
const handleEscape = (e) => {
if (e.key === 'Escape') onClose();
};
window.addEventListener('keydown', handleEscape);
return () => window.removeEventListener('keydown', handleEscape);
}, [onClose]);
const handleOverlayClick = (e) => {
if (e.target === e.currentTarget) onClose();
};
const modalContent = (
<div className="modal-overlay" onClick={handleOverlayClick}>
<div className="modal-content">
<button className="close-button" onClick={onClose}>×</button>
{children}
</div>
</div>
);
return ReactDOM.createPortal(modalContent, modalRoot);
};
// Пример использования:
function App() {
const [isModalOpen, setIsModalOpen] = useState(false);
return (
<div>
<button onClick={() => setIsModalOpen(true)}>Открыть модальное окно</button>
{isModalOpen && (
<ModalWindow onClose={() => setIsModalOpen(false)}>
<h2>Модальное окно</h2>
<p>Это содержимое модального окна.</p>
</ModalWindow>
)}
</div>
);
}
Экзаменационный билет №12
Теоретическая часть
-
Охарактеризуйте работу хука
useReducer
В чём его преимущество передuseState
и когда он наиболее уместен? -
Что такое reconciliation в React и как он влияет на производительность рендеринга? Опишите принцип работы алгоритма согласования.
Ответы на теоретическую часть:
- Хук
useReducer
используется для управления сложным состоянием, особенно если оно содержит несколько подзначений или если следующее состояние зависит от предыдущего. Он похож на Redux: принимает редюсер (функцию, которая возвращает новое состояние на основе действия) и начальное состояние. - Reconciliation — это процесс сравнения нового Virtual DOM с предыдущим, чтобы определить минимальные изменения для обновления реального DOM. Это позволяет React работать максимально производительно, избегая полной перерисовки интерфейса. Алгоритм использует два ключевых подхода:
- Сравнение по типу элемента: если типы элементов разные — узел полностью заменяется.
- Использование
key
для корректного сравнения элементов списка, что помогает React точно определить, какие элементы были изменены, добавлены или удалены.
Практическая часть
Реализуйте простую форму входа с помощью useReducer
где состояние включает email
password
isLoading
error
Добавьте валидацию email и возможность отправки формы. Форма должна иметь кнопку "Войти" и отображать ошибку, если ввод некорректный или запрос не удался.
const formReducer = (state, action) => {
switch (action.type) {
case 'change_email':
return { ...state, email: action.payload, error: '' };
case 'change_password':
return { ...state, password: action.payload, error: '' };
case 'submit_start':
return { ...state, isLoading: true, error: '' };
case 'submit_success':
return { ...state, isLoading: false };
case 'submit_error':
return { ...state, isLoading: false, error: action.payload };
case 'validate_email':
return { ...state, error: 'Введите корректный email' };
default:
return state;
}
};
const LoginForm = () => {
const [state, dispatch] = useReducer(formReducer, {
email: '',
password: '',
isLoading: false,
error: ''
});
const handleSubmit = (e) => {
e.preventDefault();
const isValidEmail = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(state.email);
if (!isValidEmail) {
dispatch({ type: 'validate_email' });
return;
}
dispatch({ type: 'submit_start' });
// Мокаем асинхронный запрос
setTimeout(() => {
if (state.password.length < 6) {
dispatch({ type: 'submit_error', payload: 'Неверный пароль' });
} else {
dispatch({ type: 'submit_success' });
alert('Вход выполнен успешно');
}
}, 1000);
};
return (
<form onSubmit={handleSubmit} style={{ maxWidth: '300px', margin: 'auto' }}>
<h2>Вход</h2>
{state.error && <div style={{ color: 'red' }}>{state.error}</div>}
<div>
<label>Email:</label>
<input
type="text"
value={state.email}
onChange={(e) => dispatch({ type: 'change_email', payload: e.target.value })}
/>
</div>
<div>
<label>Пароль:</label>
<input
type="password"
value={state.password}
onChange={(e) => dispatch({ type: 'change_password', payload: e.target.value })}
/>
</div>
<button type="submit" disabled={state.isLoading}>
{state.isLoading ? 'Загрузка...' : 'Войти'}
</button>
</form>
);
};
Экзаменационный билет №13
Теоретическая часть
-
Объясните, что такое PureComponent и React.memo. В чём их отличие и когда следует использовать каждый из них?
-
Что такое порталы в React и зачем они нужны? Приведите примеры использования.
Ответы на теоретическую часть:
-
PureComponent — это базовый класс для классовых компонентов, реализующий метод
shouldComponentUpdate()
с поверхностным сравнением props и state. Он предотвращает ненужный рендер, если данные не изменились.React.memo
— это Higher-Order Component, который применяется к функциональным компонентам и делает то же самое — сравнивает props и пропускает рендер, если они не изменились.Разница:
PureComponent
работает с классовыми компонентами.React.memo
— с функциональными.React.memo
можно расширить, передав свою функцию сравнения вторым аргументом.
- Portals в React позволяют рендерить дочерние элементы вне иерархии родительского компонента в произвольном DOM-узле. Это особенно полезно для модальных окон, уведомлений, тултипов и других UI-компонентов, которые должны быть позиционированы вне текущего контекста CSS.
Практическая часть
Создайте компонент TabPanel
принимающий массив вкладокtabs
и отображающий содержимое активной вкладки. Каждая вкладка должна иметь заголовок и содержимое. При клике на вкладку должно меняться состояние активной вкладки. Добавьте возможность отключения вкладок и стилизовать активную вкладку.
const TabPanel = ({ tabs }) => {
const [activeIndex, setActiveIndex] = useState(0);
const handleTabClick = (index) => {
if (!tabs[index].disabled) {
setActiveIndex(index);
}
};
return (
<div className="tab-panel">
<div className="tab-list" role="tablist">
{tabs.map((tab, index) => (
<button
key={index}
role="tab"
aria-selected={index === activeIndex}
disabled={tab.disabled}
onClick={() => handleTabClick(index)}
className={`tab-button ${index === activeIndex ? 'active' : ''}`}
>
{tab.title}
</button>
))}
</div>
<div className="tab-content" role="tabpanel">
{tabs[activeIndex].content}
</div>
</div>
);
};
// Пример использования:
function App() {
const tabs = [
{
title: 'Вкладка 1',
content: <p>Содержимое первой вкладки.</p>,
disabled: false
},
{
title: 'Вкладка 2',
content: <p>Содержимое второй вкладки.</p>,
disabled: false
},
{
title: 'Заблокировано',
content: <p>Эта вкладка отключена.</p>,
disabled: true
}
];
return <TabPanel tabs={tabs} />;
}
Экзаменационный билет №14
Теоретическая часть
-
Объясните, что такое
React Context API
и в каких сценариях её использование наиболее уместно. Какие ограничения имеет Context API? -
Что такое ленивая загрузка (lazy loading) компонентов в React? Как реализуется через
React.lazy()
иSuspense
Ответы на теоретическую часть:
-
- React Context API — это механизм передачи данных через дерево компонентов без необходимости явно передавать props на каждом уровне. Чаще всего используется для передачи глобального состояния, такого как тема приложения, данные авторизации, языковые настройки и т. д.
Context состоит из:
React.createContext()
— создаёт объект контекста.Provider
— компонент, который позволяет дочерним компонентам потреблять значение контекста.Consumer
или хукuseContext
— используется для чтения значения контекста.
- Ленивая загрузка (lazy loading) — это подход, при котором компоненты загружаются только при необходимости, например, при первом обращении к ним. Это улучшает производительность начальной загрузки приложения за счёт уменьшения объёма загружаемого JavaScript.
Практическая часть
Реализуйте пользовательский хук useFetch
который принимает URL и параметры запроса, и возвращает объект { data, loading, error }
Хук должен выполнять fetch-запрос, обрабатывать ошибки и поддерживать отмену запроса при размонтировании компонента.
const useFetch = (url, options = {}) => {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
let isMounted = true;
const abortController = new AbortController();
const fetchData = async () => {
try {
const response = await fetch(url, {
...options,
signal: abortController.signal
});
if (!response.ok) throw new Error(`Ошибка HTTP: ${response.status}`);
const result = await response.json();
if (isMounted) {
setData(result);
setLoading(false);
}
} catch (err) {
if (isMounted && err.name !== 'AbortError') {
setError(err.message);
setLoading(false);
}
}
};
fetchData();
return () => {
isMounted = false;
abortController.abort();
};
}, [url, options]);
return { data, loading, error };
};
Экзаменационный билет №15
Теоретическая часть
-
Что такое
React.Fragment
и зачем он используется? Приведите примеры использования и объясните, почему он предпочтительнее обёртки в виде<div>
-
Охарактеризуйте работу хука
useRef
В чём его отличие отuseState
и когда следует использовать?
Ответы на теоретическую часть:
React.Fragment
— это способ группировать несколько элементов JSX без добавления лишнего узла в DOM. Используется, когда нужно вернуть несколько элементов из компонента, но не хочется оборачивать их в дополнительный контейнер, например,<div>
, который может нарушить структуру CSS или семантику HTML.- Хук
useRef
возвращает изменяемый объект, свойство.current
которого сохраняет своё значение между рендерами. Он полезен для:- Хранения ссылок на DOM-элементы
ref={myRef}
- Хранения любого значения, которое не должно вызывать повторный рендер при его изменении в отличие от
useState
- Хранения ссылок на DOM-элементы
Практическая часть
Реализуйте пользовательский хук useDebounce
который принимает значение и задержку, и возвращает это значение с задержкой обновления. Хук должен быть полезен при реализации поиска с debounce, чтобы не отправлять запросы слишком часто.
const useDebounce = (value, delay) => {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const handler = setTimeout(() => {
setDebouncedValue(value);
}, delay);
return () => {
clearTimeout(handler);
};
}, [value, delay]);
return debouncedValue;
};
(1) Кейс: "Реализация формы фильтрации товаров с debounce и валидацией"
Описание кейса
Вы работаете над интернет-магазином, где необходимо реализовать форму поиска и фильтрации товаров. Форма должна содержать:
- Поле поиска по названию товара
- Выпадающий список для выбора категории
- Чекбокс "Только в наличии"
- Кнопку "Сбросить фильтры"
Пользователь ожидает, что результаты поиска будут обновляться динамически при вводе текста или изменении фильтров. Однако вы замечаете, что при каждом нажатии клавиши выполняется новый HTTP-запрос, что вызывает перегрузку сервера и ухудшает отзывчивость интерфейса.
Проанализировать текущую реализацию, выявить проблемы с производительностью и UX, а также предложить и внедрить оптимизации:
- Реализовать debounce для поля поиска
- Обеспечить корректную работу формы без лишних запросов
- Добавить валидацию и возможность сброса фильтров
Исходный скрипт
const ProductFilter = ({ onApplyFilters }) => {
const [filters, setFilters] = useState({
searchQuery: '',
category: 'all',
inStockOnly: false,
});
const handleChange = (e) => {
const { name, value, type, checked } = e.target;
const newValue = type === 'checkbox' ? checked : value;
setFilters((prev) => ({
...prev,
[name]: newValue,
}));
};
const handleReset = () => {
setFilters({
searchQuery: '',
category: 'all',
inStockOnly: false,
});
};
useEffect(() => {
const fetchProducts = async () => {
const response = await fetch(`/api/products?filters=${encodeURIComponent(JSON.stringify(filters))}`);
const data = await response.json();
onApplyFilters(data);
};
fetchProducts();
}, [filters, onApplyFilters]);
return (
<form className="product-filter">
<input
type="text"
name="searchQuery"
placeholder="Поиск по названию..."
value={filters.searchQuery}
onChange={handleChange}
/>
<select name="category" value={filters.category} onChange={handleChange}>
<option value="all">Все категории</option>
<option value="electronics">Электроника</option>
<option value="clothing">Одежда</option>
</select>
<label>
<input
type="checkbox"
name="inStockOnly"
checked={filters.inStockOnly}
onChange={handleChange}
/>
Только в наличии
</label>
<button type="button" onClick={handleReset}>Сбросить фильтры</button>
</form>
);
};
Анализ ситуации и выявление проблем
Проблема №1: Отсутствие debounce для поискового запроса
При каждом нажатии клавиши происходит HTTP-запрос, что вызывает перегрузку сервера.
Решение:
Добавить пользовательский хук useDebounce
чтобы откладывать выполнение запроса:
const useDebounce = (value, delay) => {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const handler = setTimeout(() => {
setDebouncedValue(value);
}, delay);
return () => clearTimeout(handler);
}, [value, delay]);
return debouncedValue;
};
Использовать его в useEffect
const debouncedSearch = useDebounce(filters.searchQuery, 500);
useEffect(() => {
// Выполняем запрос только если debouncedSearch изменился
}, [debouncedSearch]);
Проблема №2: Нет отмены предыдущего запроса при новом изменении
Старые запросы могут завершаться позже новых, приводя к некорректным данным.
Решение:
Использовать AbortController
для отмены предыдущего запроса:
useEffect(() => {
const controller = new AbortController();
const fetchData = async () => {
try {
const response = await fetch(`/api/products?filters=${JSON.stringify(filters)}`, {
signal: controller.signal,
});
const data = await response.json();
onApplyFilters(data);
} catch (err) {
if (err.name !== 'AbortError') {
console.error('Ошибка загрузки:', err);
}
}
};
fetchData();
return () => controller.abort();
}, [debouncedSearch, filters.category, filters.inStockOnly]);
Проблема №3: Форма не проверяет актуальность данных перед применением фильтров
Если значения фильтров совпадают с предыдущими — всё равно отправляется запрос.
Решение:
Сравнить текущие и предыдущие значения фильтров:
const prevFilters = usePrevious(filters); // реализация usePrevious ниже
if (isEqual(filters, prevFilters)) return;
Хук usePrevious
const usePrevious = (value) => {
const ref = useRef();
useEffect(() => {
ref.current = value;
}, [value]);
return ref.current;
};
Проблема №4: Нет минимальной длины для поискового запроса
Запросы выполняются даже при вводе одной буквы, что может быть избыточно.
Решение:
Добавить условие:
if (debouncedSearch.length > 2 || debouncedSearch === '') {
// Выполнить поиск
}
Проблема №5: Форма не блокирует ввод при загрузке данных
Пользователь может продолжать вводить, пока идёт загрузка — это может вызвать путаницу.
Решение:
Добавить состояние isLoading
и заблокировать элементы управления:
const [isLoading, setIsLoading] = useState(false);
// внутри fetchData
setIsLoading(true);
// после получения данных
setIsLoading(false);
<button disabled={isLoading} type="button" onClick={handleReset}>
{isLoading ? 'Загрузка...' : 'Сбросить фильтры'}
</button>
Обучающие моменты
- useDebounce — позволяет откладывать выполнение кода, например, при вводе текста.
- AbortController — используется для отмены асинхронных операций, таких как HTTP-запросы.
- usePrevious — помогает сохранять предыдущее значение состояния для сравнения изменений.
- Оптимизация запросов — важно избегать лишних вызовов API, особенно при частых обновлениях фильтров.
- Управление состоянием формы — лучше централизованно управлять через
useState
особенно если форма содержит несколько зависимых полей.
Дополнительные задания для самостоятельной работы
-
Реализуйте кэширование результатов поиска
Сохраняйте уже выполненные запросы и возвращайте закэшированный результат при повторном использовании тех же фильтров. -
Добавьте индикатор загрузки рядом с полем поиска
Отображайте спиннер или надпись "Идет поиск..." при выполнении запроса. -
Перепишите логику с использованием React Query или SWR
Замените ручное управление состояния и эффектов на готовое решение для управления данными. -
Добавьте поддержку пагинации
Реализуйте кнопки "Предыдущая/Следующая страница" и обновляйте параметры запроса. -
Добавьте валидацию категории перед отправкой запроса
Если категория не существует, показывайте ошибку вместо запроса. -
Сделайте форму контролируемой через URL-параметры
При открытии страницы с определёнными параметрами?search=iphone&category=electronics
автоматически устанавливайте соответствующие фильтры. -
Реализуйте локальное хранение фильтров в localStorage
При перезагрузке страницы восстанавливайте последние установленные значения фильтров.
(2) Кейс: "Реализация темизации (light/dark mode) с сохранением состояния в localStorage"
Описание ситуации
Вы работаете над веб-приложением, которое должно поддерживать две темы — светлую и тёмную. Пользователь должен иметь возможность переключать тему в интерфейсе, а его выбор должен сохраняться между сессиями.
На данный момент:
- В интерфейсе есть кнопка переключения темы.
- Тема применяется к компонентам через CSS-класс на корневом элементе.
- При перезагрузке страницы тема всегда сбрасывается на стандартную (например, light).
Ваша задача — реализовать устойчивое управление темой приложения с сохранением состояния и синхронизацией между компонентами.
Цель кейса
- Реализовать переключение темы (light/dark).
- Сохранить выбор пользователя в
localStorage
- Применить тему при монтировании компонента.
- Обеспечить доступ к текущей теме из любого компонента приложения.
Проблема №1: Нет сохранения выбора темы между перезагрузками страницы.
Решение:
Используйте localStorage
для хранения текущей темы:
localStorage.setItem('app-theme', theme);
При монтировании компонента считывайте значение:
const savedTheme = localStorage.getItem('app-theme');
if (savedTheme) setTheme(savedTheme);
Проблема №2: Тема не применяется глобально, а дублируется в разных компонентах.
Решение:
Создайте провайдер с помощью Context API
чтобы централизованно управлять темой:
<ThemeProvider>
<App />
</ThemeProvider>
Доступ к теме из любого компонента через кастомный хук:
const { theme, setTheme } = useTheme();
Проблема №3: Тема не реагирует на системные настройки пользователя (например, dark mode ОС).
Решение:
Проверьте предпочтения системы через matchMedia API
const systemPrefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
if (!savedTheme && systemPrefersDark) setTheme('dark');
Проблема №4: Изменение темы не отражается в интерфейсе (CSS не обновляется).
Решение:
Добавляйте/удаляйте CSS-классы на корневом элементе при изменении темы:
useEffect(() => {
document.documentElement.classList.remove('light', 'dark');
document.documentElement.classList.add(theme);
}, [theme]);
Проблема №5: Нет удобного способа получения текущей темы в любом компоненте.
Решение:
Создайте кастомный хук useTheme()
export const useTheme = () => {
const context = React.useContext(ThemeContext);
if (!context) throw new Error('useTheme должен использоваться внутри ThemeProvider');
return context;
};
Проблема №6: Нет кнопки переключения темы или она работает некорректно.
Решение:
Реализуйте простую кнопку:
<button onClick={toggleTheme}>
{theme === 'light' ? 'Тёмная тема' : 'Светлая тема'}
</button>
Функция toggleTheme
меняет тему:
setTheme(theme === 'light' ? 'dark' : 'light');
Проблема №7: Пользователь не видит, какая тема активна (нет визуального индикатора).
Решение:
Добавьте стилизованный индикатор или текст:
<div>Текущая тема: {theme}</div>
Или иконку солнца/луны:
{theme === 'light' ? '☀️' : '🌙'}
Обучающие моменты
Ролевая игра №1: «React-Стартап: Создание MVP за 2 недели»
Цель игры:
Научить студентов работать в команде, проектировать архитектуру приложения, разрабатывать фронтенд на React с использованием современных практик и библиотек, а также представлять результаты своей работы перед заказчиком.
Формат игры:
- Тип: Командная ролевая игра
- Длительность: 2 недели (по 3–4 академических часа в неделю)
- Количество участников: 4–6 человек в команде
- Минимальное количество игроков: 4
- Преподаватель: выступает в роли "заказчика" и "наставника"
Сеттинг:
Вы — молодая IT-стартап-команда, которая получила задание от инвестора (преподавателя) создать MVP (минимально жизнеспособный продукт) за ограниченное время. Ваша задача — спроектировать, реализовать и презентовать прототип приложения на основе технического задания.
Роли в команде:
Этапы игры:
1. Постановка задачи
- Получение ТЗ от преподавателя.
- Анализ требований, составление списка фич.
- Распределение ролей в команде.
2. Проектирование
- Создание wireframe’ов.
- Проектирование структуры приложения (компоненты, роуты, стор).
- Выбор технологий (React, TypeScript, CSS-in-JS и т.д.).
3. Разработка MVP
- Реализация базового функционала:
- Навигация
- Формы
- Данные (mock или API)
- Темизация
- Адаптивность
4. Тестирование и оптимизация
- Unit- и snapshot-тесты.
- Оптимизация производительности.
- Устранение найденных ошибок.
5. Презентация и защита
- Презентация MVP клиенту (преподавателю).
- Демонстрация ключевых возможностей.
- Ответы на вопросы.
- Обратная связь от "инвестора".
Обучающие эффекты:
Возможные проблемы и вызовы во время игры:
Интеллект-карта 1: Общий путь освоения React (Профессиональный уровень)
Ветки:
-
Основы React
- JSX
- Компоненты (функциональные и классовые)
- Props и их типизация (PropTypes, TypeScript)
- Условный рендеринг и списки
-
Состояние и жизненный цикл
- useState, useEffect
- Работа с DOM через useRef
- useReducer для сложного состояния
- Контролируемые / неконтролируемые компоненты
-
Работа с формами
- Валидация
- Реактивное обновление
- Хранение состояния формы
- Библиотеки: Formik, React Hook Form
-
Оптимизация производительности
- React.memo
- useCallback и useMemo
- Порталы и Suspense
- Ленивая загрузка (React.lazy)
-
Управление состоянием
- Context API
- Redux Toolkit
- Zustand / MobX (по выбору)
- Асинхронные эффекты (RTK Query, Thunk, Saga)
-
Роутинг
- React Router (v6/v7)
- Динамические маршруты
- Защита маршрутов
- Lazy loading страниц
-
Тестирование
- Unit-тесты (Jest, React Testing Library)
- Snapshot тесты
- Тестирование хуков и компонентов
- End-to-end тесты (Cypress, Playwright)
-
Темизация и локализация
- Темизация через Context API или CSS переменные
- i18n библиотеки (react-i18next, formatjs)
- Поддержка RTL
-
Архитектура приложений
- Разделение кода
- Слои: UI / Features / Entities / Shared
- Feature sliced design
- Модульность и переиспользуемость
-
Деплой и CI/CD
- Build-процесс (Webpack, Vite)
- Оптимизация сборки
- Деплой на Vercel, Netlify, GitHub Pages
- Настройка CI/CD (GitHub Actions, GitLab CI)
Интеллект-карта 2: Практические навыки и проекты
Ветки:
-
Мини-проекты
- Форма регистрации с валидацией
- Список задач (To-do list)
- Калькулятор
- Погода (API + темизация)
-
Средние проекты
- Интернет-магазин (каталог, корзина, фильтры)
- Чат-приложение (с WebSocket или Firebase)
- Блог с админкой
- Расписание занятий (drag & drop, календарь)
-
Большой проект (Capstone)
- SPA с авторизацией (JWT, OAuth)
- CRUD-операции
- Роутинг и защита маршрутов
- Тестирование и документация
- Деплой и оптимизация
Интеллект-карта 3: Инструменты и технологии
Ветки:
-
JavaScript / TypeScript
- ES6+ синтаксис
- Async/await, Promises
- Работа с массивами и объектами
- TypeScript (типы, интерфейсы, generics)
-
Build Tools
- Webpack
- Vite
- Babel
- ESLint / Prettier
-
CSS и стилизация
- CSS-in-JS (styled-components, emotion)
- Tailwind CSS
- BEM / SMACSS
- Анимации (Framer Motion, React Spring)
-
HTTP клиенты
- Axios
- Fetch API
- SWR / React Query
- RTK Query
-
Тестирование
- Jest
- React Testing Library
- Cypress / Playwright
- Testing Library DOM
-
Инструменты разработки
- DevTools
- React Developer Tools
- Storybook / Chromatic
- Linter, Formatter
Интеллект-карта 4: Профиль профессионального React-разработчика
Ветки:
-
Hard Skills
- Знание React Core
- Умение работать с асинхронностью
- Написание чистого, поддерживаемого кода
- Понимание принципов DRY, KISS, SOLID
- Опыт работы с REST / GraphQL API
-
Soft Skills
- Самостоятельная работа
- Работа в команде
- Чтение документации
- Решение проблем
- Презентация решений
-
Профессиональное развитие
- Изучение новых версий React (например, React 19, React Compiler)
- Участие в open-source
- Создание портфолио
- Подготовка к техническим собеседованиям
1. "React — Разработка веб-приложений" — Кайс Насир
- Тип: Учебное пособие
- Краткое описание:
Подробное руководство по созданию современных SPA с использованием React. Охватывает от базовых концепций до продвинутых паттернов, хуков, контекста, роутинга и Redux. - Для кого: Для студентов и начинающих разработчиков.
2. "React. Полное руководство" — Максимilian Шварценбах (Maximilian Schwarzmüller)
- Тип: Учебник
- Краткое описание:
Один из самых популярных курсов и книг по React. Подходит как практическое пособие по всем аспектам фреймворка: компоненты, состояние, хуки, тестирование, оптимизация, TypeScript и т.д. - Плюс: Видеокурс в дополнение к книге.
3. "React Design Patterns and Best Practices" — Michele Bertoli
- Тип: Научно-популярная / методическая литература
- Краткое описание:
Книга о проектировании приложений на React. Рассмотрены лучшие практики, шаблоны проектирования, работа с формами, стилизацией и архитектурой. - Для кого: Продвинутые разработчики, преподаватели, менторы.
4. "Learning React: Functional UI Development" — Alex Banks, Eve Porcello
- Тип: Учебное пособие
- Краткое описание:
Практический курс по созданию интерфейсов с нуля. Покрывает JSX, компоненты, работу с данными, клиентский роутинг и интеграцию с API. - Плюс: Подходит для обучения в академической среде.
5. Методические указания «Разработка одностраничных приложений на React» (авторские материалы вузов или онлайн-курсов)
- Тип: Методическое пособие
- Краткое описание:
Специализированные лабораторные работы, задачники и практические задания по темам:- Создание компонентов
- Управление состоянием
- Роутинг
- Формы и валидация
- Тестирование
- Где найти: Внутренние учебные материалы курсов по фронтенд-разработке (например, Яндекс.Практикум, Coursera, Skillbox).
- React Профессионал: Современная фронтенд-разработка с нуля до PRO
- React Fullstack Developer: Полный путь к профессии
- Мастер React: Профессиональная разработка интерфейсов
- Фронтенд-разработчик на React: Продвинутый уровень
- React Pro: Архитектура, оптимизация, производительность
- React в продакшене: Реальные практики опытного разработчика
- Профессиональный React: Разработка масштабируемых приложений
- React Developer Bootcamp: Интенсив по профессиональному уровню
- React. Уровень PRO: Масштабирование, тестирование, CI/CD
- React-архитект: Паттерны, дизайн-системы, управление состоянием
- Фронтенд на React: От Junior до Middle за 3 месяца
- React Advanced: Глубокое погружение в сложные темы
- React в реальных проектах: Кейсы, задачи, решения
- React для профессионалов: Продвинутые хуки, SSR, микросервисы
- React-мастерство: Тестирование, деплой, оптимизация
- React. Путь Senior’а: Архитектура, чистый код, шаблоны
- Разработка UI на React: Стилизация, компоненты, дизайн-системы
- React в команде: Best practices, документация, совместная работа
- React с TypeScript: Типизация в крупных приложениях
- React и экосистема: Redux, Router, Query, Formik и другие библиотеки
- SPA на React: Создание одностраничных приложений уровня PRO
- React для продвинутых: Ленивая загрузка, роутинг, серверный рендер
- React-инженер: Производительность, безопасность, доступность
- React-паттерны: Профессиональное проектирование интерфейсов
- React в Agile: Разработка интерфейсов в условиях динамических требований
Нет элементов для просмотра