Продвинутый React и Redux
Refs, context, мемоизация, паттерны HOC и render-props, а также поток данных Redux, middleware, нормализация и селекторы.
12 вопросов
JuniorТеорияОчень частоЧто такое store, actions, reducers и dispatch в Redux?
Что такое store, actions, reducers и dispatch в Redux?
Store держит всё состояние приложения как одно дерево объектов, доступное только для чтения. Action — это обычный объект, описывающий, что произошло, с полем type. Reducer — чистая функция (state, action) => newState, возвращающая следующее состояние без мутации старого.
Типичные ошибки
- ✗Мутировать объект состояния внутри reducer вместо возврата нового
- ✗Менять store без диспатча action
- ✗Класть побочные эффекты или async-вызовы внутрь reducer
Уточняющие вопросы
- →Почему reducer должен быть чистой функцией, возвращающей новое состояние?
- →Почему
dispatch— единственный санкционированный способ изменить store?
MiddleТеорияОчень частоЧем Component, PureComponent и React.memo различаются по перерендеру?
Чем Component, PureComponent и React.memo различаются по перерендеру?
Component всегда перерендеривается, когда это делает родитель. PureComponent реализует shouldComponentUpdate с поверхностным сравнением props и state, пропуская рендер, если на верхнем уровне ничего не изменилось. React.memo — аналог для функциональных компонентов, сравнивающий только props поверхностно.
Типичные ошибки
- ✗Мутировать вложенный объект props на месте, чего поверхностное сравнение не замечает
- ✗Думать, что
React.memoиPureComponentделают глубокое сравнение - ✗Передавать новый inline объект/массив/функцию props каждый рендер, ломая пропуск рендера
Уточняющие вопросы
- →Почему мутация вложенного объекта может тихо сломать пропуск рендера у
PureComponent? - →Пропускает ли
React.memoперерендер, вызванный внутренним изменениемuseState?
JuniorТеорияЧастоКакую проблему решает Context в React?
Какую проблему решает Context в React?
Context позволяет значению дойти до глубоко вложенных компонентов, не передавая его как prop через каждый уровень — он убирает prop drilling. Провайдер задаёт значение высоко в дереве, а любой потомок читает его напрямую через useContext, сколько бы слоёв ни было между ними.
Типичные ошибки
- ✗Использовать context для данных, нужных лишь паре соседних компонентов
- ✗Думать, что context заменяет менеджер состояния, а не передаёт существующие данные
- ✗Считать, что context передаёт данные вверх от ребёнка к родителю
Уточняющие вопросы
- →Какие данные хорошо ложатся в context, а какие — в props?
- →Почему context не передаёт данные от ребёнка вверх к родителю?
JuniorТеорияЧастоЧто такое refs в React и для чего их обычно используют?
Что такое refs в React и для чего их обычно используют?
Ref — это escape-hatch, дающий императивный доступ к значению, переживающему перерендеры и не вызывающему их. На host-элементе он держит сам DOM-узел — для фокуса поля, измерения раскладки или управления медиа; на классовом компоненте — его инстанс.
Типичные ошибки
- ✗Тянуться к ref ради того, что state и props уже решают декларативно
- ✗Ожидать, что мутация
ref.currentвызовет перерендер - ✗Ставить ref на функциональный компонент без
forwardRef
Уточняющие вопросы
- →Почему мутация
ref.currentнамеренно не вызывает перерендер? - →Почему функциональному компоненту нужен
forwardRef, чтобы принять ref?
MiddleТеорияЧастоСравните паттерны переиспользования React — компоненты высшего порядка и render props
Сравните паттерны переиспользования React — компоненты высшего порядка и render props
Оба разделяют сквозную логику. Компонент высшего порядка — функция, принимающая компонент и возвращающая обёрнутый с дополнительными props/поведением (например, connect); это углубляет дерево и может конфликтовать по именам props. Render props передают функцию как prop, которую компонент вызывает для отрисовки, делая поток данных явным и «слотовым», но порождая вложенность обёрток. Кастомные хуки сегодня во многом вытеснили оба для переиспользования логики.
Типичные ошибки
- ✗Объявлять HOC внутри render, что перемонтирует обёрнутый компонент каждый рендер
- ✗Думать, что HOC и render props делят состояние, а хуки — нет
- ✗Игнорировать конфликты имён props, которые HOC может внести в обёрнутый компонент
Уточняющие вопросы
- →Почему объявление HOC внутри метода render может вызывать перемонтирование?
- →Как кастомный хук переиспользует логику состояния без вложенности в дереве?
MiddleТеорияЧастоОпишите однонаправленный поток данных в контейнере состояния Redux
Опишите однонаправленный поток данных в контейнере состояния Redux
Данные текут в одну сторону. UI вызывает store.dispatch(action). Store запускает редьюсеры — чистые функции, принимающие текущий state и action и возвращающие либо тот же state, либо новый неизменяемо, никогда не мутируя старый. Store сохраняет возвращённый state и уведомляет подписчиков, которые перечитывают его и перерендериваются. State доступен только для чтения; единственный способ его изменить — задиспатчить action.
Типичные ошибки
- ✗Мутировать state внутри редьюсера вместо возврата нового неизменяемого объекта
- ✗Класть побочные эффекты или async-вызовы прямо в редьюсер вместо middleware
- ✗Считать dispatch необязательным — это единственный способ изменить state стора
Уточняющие вопросы
- →Почему редьюсеры должны быть чистыми и не мутировать предыдущий state?
- →Где в этом потоке место асинхронным эффектам вроде загрузки данных?
MiddleТеорияИногдаДля чего нужен middleware в Redux и где он стоит в потоке?
Для чего нужен middleware в Redux и где он стоит в потоке?
Middleware — это слой, перехватывающий каждый отправленный action после dispatch, но до того, как он дойдёт до reducers. Здесь живут побочные эффекты: логирование, async-вызовы, аналитика, отчёты о падениях. Каждый middleware вызывает next(action), передавая управление дальше.
Типичные ошибки
- ✗Думать, что middleware выполняется внутри или после reducers, а не до них
- ✗Забыть вызвать
next(action), молча проглотив action - ✗Считать, что активен может быть лишь один middleware, а не собранная цепочка
Уточняющие вопросы
- →Что станет с action, если middleware так и не вызовет
next? - →Почему async-библиотеки вроде thunk и saga живут в middleware?
MiddleТеорияИногдаЧто такое нормализация состояния в Redux и зачем она нужна?
Что такое нормализация состояния в Redux и зачем она нужна?
Нормализация уплощает вложенные данные в структуру, похожую на БД: каждый тип сущности лежит в справочнике по id, а связи хранятся как массивы id, а не вложенные копии. Это убирает дублирование и делает обновления дешёвыми, локальными и O(1) для поиска.
Типичные ошибки
- ✗Хранить одну запись вложенной во многих местах, так что обновление трогает все
- ✗Путать нормализацию с сериализацией или сжатием
- ✗Держать в store глубокие деревья в форме API и бороться с лавиной обновлений
Уточняющие вопросы
- →Как ключевание сущностей по id делает обновление O(1) и локальным?
- →Когда нормализация избыточна для небольшого куска состояния?
MiddleТеорияИногдаЧто заставляет компонент React перерендериться и как это меняет React.memo?
Что заставляет компонент React перерендериться и как это меняет React.memo?
Компонент перерендеривается, когда меняется его собственный state, когда перерендеривается родитель, или когда меняется потребляемый контекст. React по умолчанию НЕ сравнивает props глубоко — рендер родителя перерендеривает всех детей независимо от того, изменились ли их props. React.memo (и PureComponent/shouldComponentUpdate у классов) оборачивает компонент, чтобы пропустить перерендер, когда поверхностное сравнение props не выявило изменений.
Типичные ошибки
- ✗Считать, что React пропускает детей с неизменными props без обёртки memo
- ✗Передавать новый inline объект/массив/функцию props каждый рендер, обнуляя
React.memo - ✗Думать, что
React.memoделает глубокое сравнение, а не поверхностное
Уточняющие вопросы
- →Почему передача нового inline-стрелочного prop ломает
React.memo-ребёнка? - →Как
useCallbackпомогает удержать мемоизированного ребёнка от перерендера?
SeniorТеорияИногдаЧем различаются async-библиотеки redux-thunk и redux-saga в Redux?
Чем различаются async-библиотеки redux-thunk и redux-saga в Redux?
Оба — middleware для async-работы и побочных эффектов, ведь reducers должны оставаться чистыми. redux-thunk позволяет action creator вернуть функцию, получающую dispatch/getState — минималистично, легко освоить, идеально для простых async-потоков.
Типичные ошибки
- ✗Думать, что thunk использует генераторы или saga возвращает обычные функции, путая их
- ✗Тянуться к сложности saga на проекте с лишь простыми async-потоками
- ✗Считать, что любой из них позволяет reducers напрямую делать async-работу
Уточняющие вопросы
- →Почему декларативные эффекты saga легче юнит-тестировать, чем императивные вызовы thunk?
- →Какие async-потоки оправдывают добавленную сложность saga по сравнению с thunk?
MiddleТеорияРедкоКогда стоит брать Context в React, а когда его избегать?
Когда стоит брать Context в React, а когда его избегать?
Берите context для по-настоящему глобальных, редко меняющихся данных, которые читают многие компоненты — пользователь, тема, локаль. Избегайте для часто меняющихся или нужных лишь паре соседних: каждый потребитель перерендеривается при смене идентичности значения провайдера.
Типичные ошибки
- ✗Класть быстро меняющиеся данные в context, перерендеривая большие поддеревья
- ✗Передавать новый литерал объекта как значение провайдера на каждом рендере
- ✗Использовать context там, где хватило бы простых props или композиции
Уточняющие вопросы
- →Почему передача нового литерала объекта как значения провайдера вредит производительности?
- →Как дробление одного context на несколько ограничивает охват перерендера?
MiddleТеорияРедкоЧто такое библиотека селекторов reselect и зачем мемоизированные селекторы?
Что такое библиотека селекторов reselect и зачем мемоизированные селекторы?
reselect создаёт мемоизированные селекторы, вычисляющие производные данные из store Redux. Селектор кэширует результат и пересчитывает его только при изменении конкретных входных срезов (сравнение по ссылке), поэтому дорогие преобразования (фильтрация, сортировка, агрегация) выполняются раз, а не на каждом рендере.
Типичные ошибки
- ✗Пересчитывать производные данные в компоненте на каждом рендере вместо селектора
- ✗Возвращать новый массив или объект из обычного селектора, обнуляя мемоизацию
- ✗Думать, что
reselectмемоизирует actions, а не производное состояние
Уточняющие вопросы
- →Почему стабильная ссылка из селектора предотвращает перерендер подключённого компонента?
- →Что ломает мемоизацию, если селектор строит новый объект на каждом вызове?