🏠Домашнее задание

⚡ 1) Зачистить стейт при вылогинивании

Если вылогиниться из приложения, то таски и тудулисты, которые находятся в стейте не зачищаются. И это не есть хорошо. В данном видео arrow-up-rightописана проблема и ее реализация на redux. Ваша задача сделать это на redux toolkit

⚡2) Работа с селекторами

Рефакторим все селекторы в приложении согласно auth.selectors.ts

В данном видеоarrow-up-right (запись с урока) максимально подробно рассказываю про работу с селекторами

-----------------------------------------------------------------------------------------------------

⚡1) Intro

Давайте зайдем в компонент App.tsx и посмотрим как мы достаем данные из стейта

Казалось бы и что тут рассказывать, но на самом деле есть нюансы которые нужно знать

⚡2) useAppSelector

⚡2.1) Вводная часть

Давайте перепишем доставание isLoading вот так

Я довольно часто вижу такую запись. Почему так студенты любят писать. Допустим нам из app стейта нужно достать 3 значения (isLoading, isAppInitialized, unHandleActions)

И теперь сравним 2 варианта

Сравнивая 1 и 2 вариант, очевидно что в 1 случае кода писать меньше, именно поэтому так и любят писать.

Теперь проверьте, поменялось ли что-нибудь или нет ?

Ответ: Нет, ничего не поменялось. Значит получается без разницы как писать? А вот здесь ответ нет, разница существенная.

circle-info

На работе приложения (его логической части) это никак не скажется. А на чем скажется - на перфомансе (как часто наши компоненты перерисовываться).

⚡ 2.2) Начнем со 2 варианта Вот такой у нас будет стартовый код

Вот, что мы увидим в консоли

isLoading изменил свое состояние, соответственно компонент App перерисовался. Все логично, все хорошо.

  • теперь давайте в useEffect через 3 секунды будем менять error (вмеcто isLoading)

⚡ 2.3) Теперь все тоже самое проделаем для 1 варианта

1) Для первого варианта, когда меняем крутилку ничего не поменялось

2) Но когда мы меняем ошибку, то получим следующий итог

В App.tsx мы не достаем error, но она все равно перерисовывается 🤯🤯🤯

circle-info

Так происходит именно по причине неправильного доставания данных из стейта. Мы подписываемся в useSelector на весь app useAppSelector(state => state.app) Соответственно если в app стейте поменяется любое свойство, то все компоненты в которых данные достаются подобным образом будут перерисовываться вне зависимости используется там это свойство или нет

circle-exclamation

⚡3) Selector

Опять возвращаемcя к нашему исходному селектору

⚡3.1) Как правило в разных компонентах нам нужно доставать одинаковые данные из стейта. Т.е. Код я указал выше может использовался в 10 компонентах. А теперь представьте что у нас в приложении мы решели заменить свойство isLoading на loadingStatus. К чему это приведет?

Это приведет к тому, что нам нужно идти в 10 компонент и менять эти свойства, что не очень приятно.

⚡3.2) При каждом рендере - новая функция. Cелектор будет вызываться при каждом рендере, а не только когда обновились данные в сторе.

⚡3.3) Логика получения данных из структуры стора находится внутри компонента. Но зачем компоненту знать об этом?

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

Создадим файл app.selector.ts и вынесем туда кода доставания значения из стейта

Функции селекторы называют по разному. Встречал следующие варианты:

  • selectIsLoading

  • isLoadingSelector

  • иногда вообще в названии не указывают select (selector) и группируют все селекторы в один объект (namespace). Я так не делал никогда : )

circle-exclamation

Говоря про селекторы нельзя не упомянуть про createSelectorarrow-up-right

⚡4.1) Теория

Селекторы можно разделить на 2 типа

  • простые (обычные) селекторы - это селекторы которые просто достают данные из стейта

Такие селекторы стоит использовать всегда, когда мы напрямую ссылаемся на данные из стора. Даже если возвращаемое значение является объектом, не стоит беспокоиться - мы лишь возвращаем ссылку на уже существующий объект, который находится в стейте, так что ни к каким проблемам это не приведет.

  • сложные селекторы, это селекторы в которых мы делаем сортировку / фильтрацию или сложные вычисления

⚡4.2) Практика

triangle-exclamation

1) Захаркодим запрос за 100 колодами

2) Вынесем получение колод в селектор

3) Теперь сделаем сложный селектор в котором собственно и будем осуществлять логику по фильтрации

Теперь воспользуйтесь данным селектором в Packs.tsx. Попробуйте фильтровать по разным буквам и убедитесь, что все отрабатывает верно 👍

4) Для того, чтобы понять что собственно не так, давайте компонент Counter (мог бы быть абсолютно любой компонент в котором используется useSelector) уберем из роутинга и вставим на одном уровне с App

5) Напишем console.log('render ${component}') в Packs.tsx и Counter.tsx

И теперь измените меняйте значение Counter

Мы меняем значение счетчика, который вообще никоим боком не связан с колодами, но мы видим как она перерисовывается 🤯🤯🤯.

circle-info

Такое поведение мы получаем из-за того, что наш сложный селектор возвращает новый массив.

useSelector не просто достает данные из стейта, он еще делает подписку. И рендер в компонентах происходит когда приходит новое значение.

Чтобы сравнить какому компоненту перерисовываться, под капотом у useSelector происходит сравнение изменились данные или нет.

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

Максимально подробно эту тему освятил АйтиСиняк

6) И вот чтобы избежать вот такого поведения нам и нужен createSelector

circle-info

createSelector - это функция из библиотеки reselect, которая позволяет создавать селекторы в Redux-приложениях. Селекторы используются для извлечения данных из хранилища Redux, а createSelector помогает оптимизировать производительность приложения, кэшируя результаты вызова селекторов и предотвращая повторные вычисления.

По итогу получим вот такой результат 🚀

🔗 Примеры работы с useSelector из документацииarrow-up-right

☝ Вывод по использованию createSelect такой

1) Используйте мемоизированные селекторы когда:

  • В селекторе есть тяжелые вычисления (фильтрация, сортировка, сложное преобразование данных, и так далее)

  • Результатом вызова селектора является объект. Ну и конечно же, это касается массивов и различных структур вроде Set и Map, так как они тоже являются объектами.

2) Есть мнение о том чтобы без анализа селектора всегда использовать reselectarrow-up-right

Last updated