Last updated
Last updated
Если вылогиниться из приложения, то таски и тудулисты, которые находятся в стейте не зачищаются. И это не есть хорошо. В данном описана проблема и ее реализация на redux. Ваша задача сделать это на redux toolkit
Рефакторим все селекторы в приложении согласно auth.selectors.ts
-----------------------------------------------------------------------------------------------------
Давайте зайдем в компонент App.tsx
и посмотрим как мы достаем данные из стейта
Казалось бы и что тут рассказывать, но на самом деле есть нюансы которые нужно знать
⚡2.1) Вводная часть
Давайте перепишем доставание isLoading
вот так
Я довольно часто вижу такую запись. Почему так студенты любят писать. Допустим нам из app стейта нужно достать 3 значения (isLoading
, isAppInitialized
, unHandleActions
)
И теперь сравним 2 варианта
Сравнивая 1 и 2 вариант, очевидно что в 1 случае кода писать меньше, именно поэтому так и любят писать.
Теперь проверьте, поменялось ли что-нибудь или нет ?
Ответ: Нет, ничего не поменялось. Значит получается без разницы как писать? А вот здесь ответ нет, разница существенная.
На работе приложения (его логической части) это никак не скажется. А на чем скажется - на перфомансе (как часто наши компоненты перерисовываться).
⚡ 2.2) Начнем со 2 варианта Вот такой у нас будет стартовый код
Вот, что мы увидим в консоли
isLoading
изменил свое состояние, соответственно компонент App перерисовался. Все логично, все хорошо.
теперь давайте в useEffect через 3 секунды будем менять error (вмеcто isLoading
)
⚡ 2.3) Теперь все тоже самое проделаем для 1 варианта
1) Для первого варианта, когда меняем крутилку ничего не поменялось
2) Но когда мы меняем ошибку, то получим следующий итог
В App.tsx
мы не достаем error, но она все равно перерисовывается 🤯🤯🤯
Так происходит именно по причине неправильного доставания данных из стейта. Мы подписываемся в useSelector на весь app
useAppSelector(state => state.app)
Соответственно если в app стейте поменяется любое свойство, то все компоненты в которых данные достаются подобным образом будут перерисовываться вне зависимости используется там это свойство или нет
Берем максимально точечно данные из стейта
Никогда не используем деструктуризация в селекторах (Можно этим правилом пренебречь в том случае, если уверены, что все свойства стейта используются в компоненте)
Опять возвращаемcя к нашему исходному селектору
⚡3.1) Как правило в разных компонентах нам нужно доставать одинаковые данные из стейта. Т.е. Код я указал выше может использовался в 10 компонентах.
А теперь представьте что у нас в приложении мы решели заменить свойство isLoading
на loadingStatus.
К чему это приведет?
Это приведет к тому, что нам нужно идти в 10 компонент и менять эти свойства, что не очень приятно.
⚡3.2) При каждом рендере - новая функция. Cелектор будет вызываться при каждом рендере, а не только когда обновились данные в сторе.
⚡3.3) Логика получения данных из структуры стора находится внутри компонента. Но зачем компоненту знать об этом?
По этим причинам селекторы выносят в отдельные функции, которые в принципе так и называют.
Создадим файл app.selector.ts
и вынесем туда кода доставания значения из стейта
Функции селекторы называют по разному. Встречал следующие варианты:
selectIsLoading
isLoadingSelector
иногда вообще в названии не указывают select (selector) и группируют все селекторы в один объект (namespace). Я так не делал никогда : )
Все селекторы выносим в файл с селекторами
Селекторы кладем в отдельные файлы соответствующие фиче.
⚡4.1) Теория
Селекторы можно разделить на 2 типа
простые (обычные) селекторы - это селекторы которые просто достают данные из стейта
Такие селекторы стоит использовать всегда, когда мы напрямую ссылаемся на данные из стора. Даже если возвращаемое значение является объектом, не стоит беспокоиться - мы лишь возвращаем ссылку на уже существующий объект, который находится в стейте, так что ни к каким проблемам это не приведет.
сложные селекторы, это селекторы в которых мы делаем сортировку / фильтрацию или сложные вычисления
⚡4.2) Практика
Задача Отображать только те колоды у которых в имени содержится буква f.
в проекте с карточками поиск, фильтрации, сортировка реализована на сервере, но ради примера давайте будем с сервера запрашивать 100 колод и фильтровать их по имени локально.
1) Захаркодим запрос за 100 колодами
2) Вынесем получение колод в селектор
3) Теперь сделаем сложный селектор в котором собственно и будем осуществлять логику по фильтрации
Теперь воспользуйтесь данным селектором в Packs.tsx. Попробуйте фильтровать по разным буквам и убедитесь, что все отрабатывает верно 👍
4) Для того, чтобы понять что собственно не так, давайте компонент Counter
(мог бы быть абсолютно любой компонент в котором используется useSelector) уберем из роутинга и вставим на одном уровне с App
5) Напишем console.log('render ${component}')
в Packs.tsx и Counter.tsx
И теперь измените меняйте значение Counter
Мы меняем значение счетчика, который вообще никоим боком не связан с колодами, но мы видим как она перерисовывается 🤯🤯🤯.
Такое поведение мы получаем из-за того, что наш сложный селектор возвращает новый массив.
useSelector не просто достает данные из стейта, он еще делает подписку. И рендер в компонентах происходит когда приходит новое значение.
Чтобы сравнить какому компоненту перерисовываться, под капотом у useSelector происходит сравнение изменились данные или нет.
Сравнение под капотом происходит по ссылке, а как мы знаем объекты / массивы сравниваются по ссылке и два одинаковых массива никогда не будут равны.
Максимально подробно эту тему освятил АйтиСиняк
6) И вот чтобы избежать вот такого поведения нам и нужен createSelector
createSelector
- это функция из библиотеки reselect
, которая позволяет создавать селекторы в Redux-приложениях. Селекторы используются для извлечения данных из хранилища Redux, а createSelector
помогает оптимизировать производительность приложения, кэшируя результаты вызова селекторов и предотвращая повторные вычисления.
По итогу получим вот такой результат 🚀
☝ Вывод по использованию createSelect такой
1) Используйте мемоизированные селекторы когда:
В селекторе есть тяжелые вычисления (фильтрация, сортировка, сложное преобразование данных, и так далее)
Результатом вызова селектора является объект. Ну и конечно же, это касается массивов и различных структур вроде Set и Map, так как они тоже являются объектами.
В (запись с урока) максимально подробно рассказываю про работу с селекторами
Говоря про селекторы нельзя не упомянуть про
🔗
2)