Как улучшить использование селекторов Redux и куда вынести логику обращения к ним?
Что проверяют
Понимаете ли вы, почему селекторы вызывают лишние перерисовки и где им место в структуре проекта. Следом почти всегда спрашивают, чем плох useSelector(state => state.items.filter(...)) и как сделать селектор с параметром.
Как отвечать
Сначала механика: useSelector запускается после каждого dispatch и сравнивает результат с предыдущим по ссылке. Если селектор каждый раз возвращает новый массив или объект, компонент перерисовывается на любое действие в сторе, даже чужое.
Дальше улучшения:
- мемоизация: производные данные считать через
createSelector, он входит в Redux Toolkit. Результат пересчитывается только при смене входных срезов; - селектор с параметром: в Reselect 4 кеш помнил один последний вызов, и общий селектор для карточек с разными
idпостоянно сбрасывался. В Reselect 5 (Redux Toolkit 2) по умолчанию стоитweakMapMemoize, он хранит результаты для разных аргументов, но фабрика селекторов вuseMemoостаётся самым предсказуемым вариантом; - сравнение: если нужно вернуть несколько полей объектом, передать
shallowEqualвторым аргументомuseSelectorили разбить на несколько вызовов; - размещение: селекторы живут рядом со слайсом, в Redux Toolkit 2 их можно объявить в поле
selectorsуcreateSlice. Компонент не знает форму стейта, он зовётselectVisibleTodos; - свои хуки: частый доступ оборачивают в
useCurrentUser(), а типизированный хук получают черезuseSelector.withTypes<RootState>(); - нормализация:
createEntityAdapterдаёт готовыеselectByIdиselectAll.
connect и mapStateToProps в новом коде уже не нужны, рекомендованный путь это хуки.
Где спотыкаются
Оборачивают в createSelector каждый тривиальный доступ вроде state => state.user.name. Мемоизация тут ничего не даёт, а кода становится больше.
Пишут функцию результата, которая просто возвращает свой вход, (items) => items. Reselect 5 в режиме разработки прямо предупреждает, что такой селектор бесполезен.
Хранят в сторе производные данные, например отфильтрованный список рядом с исходным, вместо того чтобы вычислять их селектором. Два источника правды рано или поздно расходятся.