> Что делают хуки useSelector и useDispatch в Redux (React)

Уровень: senior · Роль: frontend · Категория: Технические вопросы

Компании: Kvando Technologies

Стек: React

> Пример ответа

Короткий ответ

useSelector и useDispatch - это хуки из библиотеки react-redux, которые заменяют connect и паттерн HOC. useSelector принимает селектор-функцию и подписывает компонент на изменения нужной части Redux store. useDispatch возвращает ссылку на функцию dispatch, позволяя отправлять actions без привязки к store через контекст. Оба хука оптимизируют ререндеры и упрощают работу с Redux в функциональных компонентах.

Подробное объяснение

useSelector - это хук, который принимает селектор (функцию, получающую весь state и возвращающую его часть) и опционально функцию сравнения (по умолчанию - строгое равенство ===). Он автоматически подписывает компонент на Redux store и вызывает ререндер только когда результат селектора изменился. Это позволяет избежать лишних ререндеров, в отличие от mapStateToProps, где сравнение было поверхностным.

useDispatch возвращает стабильную ссылку на dispatch из store. В отличие от useSelector, он не вызывает ререндер при изменении store, так как сам dispatch не меняется. Это эквивалент mapDispatchToProps без необходимости оборачивать actions в bindActionCreators.

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

На практике

Для senior-уровня важно понимать trade-off: useSelector подписывается на весь store, но сравнивает только результат селектора. Это может привести к проблемам, если селектор возвращает новый объект при каждом вызове - компонент будет ререндериться на каждое изменение store. Решение - использовать shallowEqual из react-redux или мемоизированные селекторы.

useDispatch не требует мемоизации, так как ссылка стабильна. Однако при передаче dispatch в дочерние компоненты через props стоит помнить, что это не вызовет лишних ререндеров.

Пример кода

JSX
import { useSelector, useDispatch, shallowEqual } from 'react-redux';
import { increment, decrement } from './counterSlice';
function Counter() {
// Селектор с shallowEqual для объекта
const { value, status } = useSelector(
state => ({ value: state.counter.value, status: state.counter.status }),
shallowEqual
);
const dispatch = useDispatch();
return (
<div>
<span>{value} ({status})</span>
<button onClick={() => dispatch(increment())}>+</button>
<button onClick={() => dispatch(decrement())}>-</button>
</div>
);
}

Как отвечать на собеседовании

Начни с определения хуков и их отличия от connect. Затем объясни механизм подписки и сравнения в useSelector. Упомяни проблемы с ререндерами и способы их решения (shallowEqual, reselect). Для useDispatch подчеркни стабильность ссылки. Приведи пример с оптимизацией. Заверши упоминанием, что эти хуки - часть react-redux 7+ и требуют Provider на верхнем уровне.

Что проверяет интервьюер

  • Понимание работы React-Redux под капотом (контекст, подписка, сравнение).
  • Знание механизма ререндеров и оптимизации.
  • Умение выбирать между useSelector и connect в зависимости от ситуации.
  • Понимание разницы между строгим и поверхностным сравнением.
  • Знание альтернатив (например, useStore для доступа к store без подписки).

Типичные ошибки

  • Создание нового объекта в селекторе без shallowEqual - приводит к бесконечным ререндерам.
  • Передача dispatch в useEffect как зависимости - хотя ссылка стабильна, это избыточно.
  • Использование useSelector для всего store без селекции - подписка на изменения любой части store.
  • Забывание, что useSelector не эквивалентен mapStateToProps с areStatePropsEqual - по умолчанию строгое сравнение.
  • Попытка использовать useDispatch внутри условных блоков - нарушение правил хуков.

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью