Не угадал, но если подумать, то все становится очевидно. Мемоизированный selectSubtotal вызывается дважды: из selectTotal и selectTax, т.е. время на чтение данных из памяти нужно умножать на 2, это будет уже 1.72 секунды. Т.к. теперь каждую итерацию нужно считать значения для двух селекторов (selectTotal и selectTax), то и временные расходы на это будут больше, чем на расчет значения лишь одного значения для селектора selectTotal. Если на подсчет значения селектора selectTotal уходит 0.28 секунды, то 0.13 секунды уходит на подсчет значения селектора selectTax.
С мемоизацией такая интересная штука, что выполнение в миллионную долю секунды - это очень быстро. Погрешность во времени выполнении на таких значениях несущественна. Зато взяв за правило всё мемоизировать вы с меньшей вероятностью столкнётесь с ситуацией, что у вас тормозит приложение из-за неэффективной работы в каких-то случаях. Такая стратегия эффективна для промышленной разработки. Единственная причина не делать этого - писать меньше кода. И тут наиболее интересным представляется проект React Forget, который по идее возьмёт это на себя. Правда, в случае Редакса, возможно, нужна будет отдельная реализация или плагин.
Привет! ;) Все не совсем так, как рассказал АйТи-Синяк ... Весь подвох заключается в последнем селекторе selectTotal. Именно он испортил бенчмарк, и именно его надо было оставлять единственным мемоизированным. Итак, по порядку: const selectTotal = createSelector( selectSubtotal, selectTax, (subtotal, tax) => ({ total: subtotal + tax }) ) Обратите внимание, что собственно последний селектор возвращает не просто число, а возвращает объект. Если мы selectTotal переписываем без createSelector: const selectTotal = state => ({ total: selectSubtotal(state) + selectTax(state) }); то, каждый вызов этого селектора будет возвращать новый объект (новую ссылку). Кстати, если мы начинаем создавать 1 миллиард объектов, то мы нагрузим свой движок упражнениями по управлению памятью, а еще де-оптимизируем наш бенчмарк (в случае с мемоизацией там вообще могло дойти до возвращения константы после, скажем, 100 тыс. итерации). Ну, и далее очевидно, если у нас будет компонент подписанный на selectTotal, то он будет рендериться при каждом dispatch-е, даже если state не менялся (ага, dispatch вызывает подписчиков даже, если state не поменялся: github.com/reduxjs/redux/blob/master/src/createStore.ts#L257). Собственно, reselect не столько про производительность, сколько про мемоизацию ссылок и предотвращение лишних рендеров. Так, что createSelector очень даже надо использовать для селекторов, возвращающих ссылки.
В данном видео, я рассматривал reselect в вакуме. Чтобы показать людям, что он не так предсказуем как кажется. Видео о reselect в рамках React, будет еще отдельным видео. Где конечно обсудим лишние рендеры :)
@@it-sin9k как работает реселект очень хорошо показано -- єто бесспорно. Но, все же давать оценку, что он не так предсказуем, без понимания того, для чего он нужен -- это несколько ... поспешно. Так, что ждем новое видео )
кажется, в реакт приложении это всё таки имеет смысл: из redux доки: "when an action is dispatched to the Redux store, useSelector() only forces a re-render if the selector result appears to be different than the last result. The default comparison is a strict === reference comparison. With useSelector(), returning a new object every time will always force a re-render by default... Call useSelector() multiple times, with each call returning a single field value If you want to retrieve multiple values from the store, you can Use Reselect or a similar library to create a memoized selector that returns multiple values in one object, but only returns a new object when one of the values has changed. Пример с 99999999 пересчетами не актуален в веб-приложениях. А перерендеры - это актуально.
Про рендеры и т.д. будет в следующей части реселкта :) а по поводу работы useSelector, мы это уже рассмотрели в предыдущих видео: th-cam.com/video/SVG-x-4BQic/w-d-xo.html
Спасибо за контент. Я вообще-то думал, что реселект нужен для оптимизации рендеров Реакта за счёт мемоизаиции селекторов, а не для кеширования вычислений. Но референс на доку снимает все вопросы )))
Я думаю, что дорогой является не взятие мемоизированного значения и не вычисление, а операция сравнения для того чтоб понять надо ли брать мемоизированное значение или надо проводить вычисление. Тоесть если взять третий пример (где selectTotal) не мемоизирован, то операция сравнения входных данных для проверки совпадают ли они с мемоизированным входом забрали львиную часть времени на вычисления...
Представлена не совсем корректная схема работы селектора. Когда селектор вызывается повторно то он начинает процедуру сравнения данных из входящих селекторов и тем самым запрашивает данные у них триггеря туже процедуру. В итоге когда повторно вызывается selectTotal по прежнему вызываются и все остальные селекторы. Поэтому возникает такая разница между 3 и 0 селекторов, на проверку данных тратиться больше времени чем на их вычисление. Но когда количество итемов увеличилось до 10 то вычисления стали занимать больше времени чем их проверка и результат конкретно изменился при отсутствии селекторов. А при наличии селекторов время не изменилось так как айтемы считались один раз, а всё остальное время работали одинаковые проверки на схожесть входных данных и разница одного вычисления между 2 и 10 айтемами незначительна.
Также замечу что если селектор создаёт объект или массив то возврат замемоизированного значения сыграет в плюс так как лишит лишних ререндеров из-за того что useSelector будет возвращать хоть и такой же но новый объект/массив. Поэтому пример из документации будет работать производительнее так как он в конце возвращает замемоизированный объект и не будет ререндерить компонент))
Также вот пару основных признаков что вам нужно обернуть в createSelector: 1) У вас в селекторе производиться большое количество вычислений(много слаживаете, перемножаете, делите, объединяете строки) 2) Если у вас в селекторе есть цикл то в 99.99% случаев он делает больше действий чем проверка входных данных и мемоизация будет благом 3) если селектор возвращает массив или объект который был создан в теле селектора. Зачастую там будут возвращаться одинаковые но идентичные сущности.
И лайфхак в догонку: Если у вас в селекторе есть что-то типа такого: return myList || []; Или такого: return myObj || {}; То лучше вместо того чтобы создавать пустые сущности положите в константы EMPTY_ARR и EMPTY_OBJ и возвращайте их. Это может спасти вас от кучи лишних пересчётов селекторов и ререндеров.
@@azad0808 нет, он сравнивает их по тождественности. Поэтому и нужно мемоизировать возвращаемые объекты и массивы чтобы другие селекторы не перевыполнялись
Привет. У меня вопрос, до ответа на который у меня разобраться не получается. У меня есть переменая, значения для которой я принимаю из createSelector передавая туда несколько других значений. Например это функция перевода, обёрнутая в createSelector, которая получает на вход объект фраз, ключи пути, фразу и объект переменных для вставки через замеру в результирующую строку. Теперь во всех местах где используется перевод я использую получается мемоизацию... но в упор не понимаю где хранится предыдущее состония вычисления и сама функция, если при просчёте компонента внутри переменной уже строковое значение. const translate = createSelector( парамсы => код и возврат результата) const phrase = translate(парамсы) - при это фраза это строка и в себе функцию не содержит, где тогда хранится предыдущее вычисленное значение?
Очень нравятся ваши видео, но если честно пример не очень корректный. Вы ведь не на бэкенде используете реселект с миллиардом операций. Думаю потеря времени на ререндер будет гораздо существенней чем экономя времени на кеширования реселект. Ps: не уверен что правильно именно так делать бенчмарк, разве у js нет таких понятий как прогрев? Или компиляция часто используемых функций в машинный код, инлайнинг итд.
Все верно про рендер. В рамках этого видео, хотел показать, что мемоизация не бесплатная на реальных цифрах. Да и показать, что иногда кажется, очевидно как работает инструмент, а на самом деле все немного сложнее. Чтобы показать всю историю с рендерами, я записал еще одно видео, показывающее какую именно проблему решает реселект: th-cam.com/video/tbfo28Q5eag/w-d-xo.html И собственно сейчас готовлю видео, про сам реселект в рамках React По поводу измерений, было много комментариев на эту тему, поэтому записал еще одно видео с более точными бенчмарками: th-cam.com/video/ZVSJckibKe8/w-d-xo.html
А почему нельзя просто в реакте производить нужные вычисления из под useMemo к примеру. Тогда вы будем использовать только простые селекторые и в них самих ничего делать не будем. Следовательно не будет лишних вызовов из редукса. А лишние пересчеты самого реакта мы отметаем либо useMemo либо ключами при list rendering
Вы все правильно говорите, так и стоит поступать. Есть лишь один момент с селекторами. Иногда нужно рассчитать итоговую сумму товаров, с учетом карзины, скидок и т.д.. И эту итоговую сумму нужно показать в нескольких местах, абсолютно разных компонентах. В таком случае проще держать эту информацию в селекторах и делиться ей между компонентами
у меня только один вопрос, не как не могу понять зачем использовать что то не по назначению, а патом жаловатся на проблемы?) useSelector (СЛОВО selector) не филр, не мутатор, не что то еще а именно selector... что касается удобства, в чем проблема отдельно отфилтровать? или создать хук в катором это делать? (это косательно реакт)
зачаствую нам нужен вычисленный селектор в многих местах. Например totalPrice. Не хочется ее вычислять несколько раз в разных местах. Куда удобнее посчитать 1 раз и в остальных местах отдавать значение из кэша
@@it-sin9k а что мешает в initialState добавить totalPrice? и в редюсере при добавлении в массив price новой цены обновить totalPrice, потому как примая зависимость totalPrice prices
@@armensargsyan8981 От данного подхода давно отказались. У него есть 2 проблемы: - totalPrice может высчитываться из допустим 5-6 параметров (цены, скидки, время суток и т.д.). В итоге на любой из экшенов обновления любого из полей надо обновлять и totalPrice. А если еще какой-то из полей надо хранить в каком то другом редьюсере, то нужно в экшен еще пробрасывать значение всех нужных полей. В итоге увеличивается шанс, что totalPrice будет не настоящий. Поэтому все и используют вычисляемый селектор, вместо хранения. Чтобы избежать нескольких источников истины и их синхронизации - 2-ая проблема, это получится, что в reducer будет хранится какая то бизнес логика. А от этого давно вроде все решили избавляться. Не местой бизнес логике в редьюсере
@@it-sin9k можно все это обойти, во первых вынести totalPrice в отдельный reducer (конечно ломается логическая взоимосвяз между prices totalPrice что плохо, но думаю приемлимо, так как он зависит еще и от 5-6 полей которые в других редюсерах), и что то новое но все же(использовать некий вычислительный компонент(watcher) который нечего не рендерит а только диспатчит totalPrice при изменении 5-6 пропсов): по итогу вычисляется только единожды, и все работает как задумано. НО огромное спасибо!!! за обяснение что как, понял смысл селекторов и createSelector-а, еще раз спасибо!
Я тоже не угадал) Спасибо за видео, Саш. Можешь снять про recoilJS? Она еще находится у меты под тегом экспериментального см, но выглядит уж очень любопытно 👀
@@it-sin9k интереснее не значит эффективная) каждая решает какие-то свои задачи, а превью вроде как всегда показывает самые лучшие юз кейсы без случаев когда НЕ стоит её использовать как мы узнали из сегодняшнего видео)
@@grandphone3585 да, я знаком с подобного рода видео. Они очень поучительны. И конечно я не могу гарантировать, что мои бенчмарки правдивы. Но и говорить, что именно эти бенчмарки не отражают действительность мы тоже не можем. Далее напрашивается вопрос, а почему же я в итоге решил записать подобного рода видео. Основной мотивацией служили косвенные признаки. Я делал разного рода бенчмарки, и общая динамика отражала, идеи которые заложены в этом коде. Да действительно возможно 99_999_999 выполняются за иное количество времени, чем у меня в видео, но мне тут были важны не абсолютные значения, а скорее общая динамика (быстрее или медленее код выполняется). Поэтому для меня это было убедительным доводом, чтобы записать такого рода видео
@@it-sin9k я не спорю с относительными цифрами. Просто в видео подчеркивается, что все выполняется очень быстро хотя так как функций не имеют сайд эффектов, то v8 их выполнил только несколько раз. А в случае с функциями без мемоизации у него хуже вышло В целом из ролика следует, что преждевременной оптимизацией заниматься не стоит
Wtf, а что насчёт лишних ререндоров, я так понял их не будет но только если мы будет возвращать наружу значение которое было взято из createSelector. Эта тема не была поднята в видео но я считаю что это важно.
Кстати есть также возможность добавить колбек снаружи в useSelector-e вторым параметром, разве это тоже не своего рода мемоизация? Тот колбек должен отвечать за перерисовку компоненты... А видео больше про оптимизацию селекторов... Хотя тот колбек своего рода тоже оптимизация)) Интересно мнение автора.
@@valentynlugovyi4789 Про useSelector у нас есть отдельное видео, где как раз упоминается второй параметр (th-cam.com/video/SVG-x-4BQic/w-d-xo.html). По факту вы правы, этот колбек нужен именно для упразднения лишних рендеров :)
@@hihoho1578 Ну вот Ситнику настолько не понравились отдельные проблемы эффектора (практически нельзя уменьшить размер), что даже написал свой Наностор.
Не угадал, но если подумать, то все становится очевидно.
Мемоизированный selectSubtotal вызывается дважды: из selectTotal и selectTax, т.е. время на чтение данных из памяти нужно умножать на 2, это будет уже 1.72 секунды.
Т.к. теперь каждую итерацию нужно считать значения для двух селекторов (selectTotal и selectTax), то и временные расходы на это будут больше, чем на расчет значения лишь одного значения для селектора selectTotal.
Если на подсчет значения селектора selectTotal уходит 0.28 секунды, то 0.13 секунды уходит на подсчет значения селектора selectTax.
Закрепил :)
фиговое обьяснение.
@@MDFireX5 ну так объясни лучше.
так легко все оказывается! я все понял, спасибо
браво, думал раскидаю все примеры. В итоге вынес много нового
Спасибо!
Хотелось бы видео про микрофронтенды с использованием single-spa. До сих пор не могу найти годный контент про эту тему
Последние пол года пилю проект с использование ModuleFederation для микрофронтов) там действительно есть свои нюансы
Расскажи тогда про moduleFederation
@@Catafey1 Очередь из тем уже очень велика) сам иногда не знаю, какую следующую возьму тему)
@@it-sin9k бери moduleFederation :)
@@cikada3398 Надо за нее тоже взяться) но ближайшие три темы я уже запланировал)
опять шик блеск, глубоко и с разумом, спасибо 👍
С мемоизацией такая интересная штука, что выполнение в миллионную долю секунды - это очень быстро. Погрешность во времени выполнении на таких значениях несущественна. Зато взяв за правило всё мемоизировать вы с меньшей вероятностью столкнётесь с ситуацией, что у вас тормозит приложение из-за неэффективной работы в каких-то случаях. Такая стратегия эффективна для промышленной разработки. Единственная причина не делать этого - писать меньше кода. И тут наиболее интересным представляется проект React Forget, который по идее возьмёт это на себя. Правда, в случае Редакса, возможно, нужна будет отдельная реализация или плагин.
Хороший комментарий, эти темы планирую затронуть в следующем видео про reselect :)
Спасибо за подробный обзор Reselect
Привет! ;)
Все не совсем так, как рассказал АйТи-Синяк ...
Весь подвох заключается в последнем селекторе selectTotal. Именно он испортил бенчмарк, и именно его надо было оставлять единственным мемоизированным.
Итак, по порядку:
const selectTotal = createSelector(
selectSubtotal,
selectTax,
(subtotal, tax) => ({ total: subtotal + tax })
)
Обратите внимание, что собственно последний селектор возвращает не просто число, а возвращает объект. Если мы selectTotal переписываем без createSelector:
const selectTotal = state => ({ total: selectSubtotal(state) + selectTax(state) });
то, каждый вызов этого селектора будет возвращать новый объект (новую ссылку). Кстати, если мы начинаем создавать 1 миллиард объектов, то мы нагрузим свой движок упражнениями по управлению памятью, а еще де-оптимизируем наш бенчмарк (в случае с мемоизацией там вообще могло дойти до возвращения константы после, скажем, 100 тыс. итерации).
Ну, и далее очевидно, если у нас будет компонент подписанный на selectTotal, то он будет рендериться при каждом dispatch-е, даже если state не менялся (ага, dispatch вызывает подписчиков даже, если state не поменялся: github.com/reduxjs/redux/blob/master/src/createStore.ts#L257).
Собственно, reselect не столько про производительность, сколько про мемоизацию ссылок и предотвращение лишних рендеров.
Так, что createSelector очень даже надо использовать для селекторов, возвращающих ссылки.
В данном видео, я рассматривал reselect в вакуме. Чтобы показать людям, что он не так предсказуем как кажется. Видео о reselect в рамках React, будет еще отдельным видео. Где конечно обсудим лишние рендеры :)
@@it-sin9k как работает реселект очень хорошо показано -- єто бесспорно.
Но, все же давать оценку, что он не так предсказуем, без понимания того, для чего он нужен -- это несколько ... поспешно.
Так, что ждем новое видео )
Я после этого выпуска прослезился и таки подписался на патреон)
Спасибо за подписку!!!
кажется, в реакт приложении это всё таки имеет смысл:
из redux доки:
"when an action is dispatched to the Redux store, useSelector() only forces a re-render if the selector result appears to be different than the last result. The default comparison is a strict === reference comparison. With useSelector(), returning a new object every time will always force a re-render by default...
Call useSelector() multiple times, with each call returning a single field value
If you want to retrieve multiple values from the store, you can Use Reselect or a similar library to create a memoized selector that returns multiple values in one object, but only returns a new object when one of the values has changed.
Пример с 99999999 пересчетами не актуален в веб-приложениях. А перерендеры - это актуально.
Про рендеры и т.д. будет в следующей части реселкта :)
а по поводу работы useSelector, мы это уже рассмотрели в предыдущих видео:
th-cam.com/video/SVG-x-4BQic/w-d-xo.html
Спасибо за контент. Я вообще-то думал, что реселект нужен для оптимизации рендеров Реакта за счёт мемоизаиции селекторов, а не для кеширования вычислений. Но референс на доку снимает все вопросы )))
Значит не зря делал это видео)
Я думаю, что дорогой является не взятие мемоизированного значения и не вычисление, а операция сравнения для того чтоб понять надо ли брать мемоизированное значение или надо проводить вычисление. Тоесть если взять третий пример (где selectTotal) не мемоизирован, то операция сравнения входных данных для проверки совпадают ли они с мемоизированным входом забрали львиную часть времени на вычисления...
не очень уловил идею. Сравнение же идет по простому тройному ровно. Как это может быть дорого?
Представлена не совсем корректная схема работы селектора. Когда селектор вызывается повторно то он начинает процедуру сравнения данных из входящих селекторов и тем самым запрашивает данные у них триггеря туже процедуру. В итоге когда повторно вызывается selectTotal по прежнему вызываются и все остальные селекторы.
Поэтому возникает такая разница между 3 и 0 селекторов, на проверку данных тратиться больше времени чем на их вычисление.
Но когда количество итемов увеличилось до 10 то вычисления стали занимать больше времени чем их проверка и результат конкретно изменился при отсутствии селекторов. А при наличии селекторов время не изменилось так как айтемы считались один раз, а всё остальное время работали одинаковые проверки на схожесть входных данных и разница одного вычисления между 2 и 10 айтемами незначительна.
Также замечу что если селектор создаёт объект или массив то возврат замемоизированного значения сыграет в плюс так как лишит лишних ререндеров из-за того что useSelector будет возвращать хоть и такой же но новый объект/массив.
Поэтому пример из документации будет работать производительнее так как он в конце возвращает замемоизированный объект и не будет ререндерить компонент))
Также вот пару основных признаков что вам нужно обернуть в createSelector:
1) У вас в селекторе производиться большое количество вычислений(много слаживаете, перемножаете, делите, объединяете строки)
2) Если у вас в селекторе есть цикл то в 99.99% случаев он делает больше действий чем проверка входных данных и мемоизация будет благом
3) если селектор возвращает массив или объект который был создан в теле селектора. Зачастую там будут возвращаться одинаковые но идентичные сущности.
И лайфхак в догонку:
Если у вас в селекторе есть что-то типа такого:
return myList || [];
Или такого:
return myObj || {};
То лучше вместо того чтобы создавать пустые сущности положите в константы EMPTY_ARR и EMPTY_OBJ и возвращайте их. Это может спасти вас от кучи лишних пересчётов селекторов и ререндеров.
@@MrMultiCraftingа как селектор понимает что данные не изменились получеется каждый раз проводит глубокое сравнивение?, а это ведь ресурсоемко.
@@azad0808 нет, он сравнивает их по тождественности. Поэтому и нужно мемоизировать возвращаемые объекты и массивы чтобы другие селекторы не перевыполнялись
Привет. У меня вопрос, до ответа на который у меня разобраться не получается.
У меня есть переменая, значения для которой я принимаю из createSelector передавая туда несколько других значений. Например это функция перевода, обёрнутая в createSelector, которая получает на вход объект фраз, ключи пути, фразу и объект переменных для вставки через замеру в результирующую строку. Теперь во всех местах где используется перевод я использую получается мемоизацию... но в упор не понимаю где хранится предыдущее состония вычисления и сама функция, если при просчёте компонента внутри переменной уже строковое значение.
const translate = createSelector( парамсы => код и возврат результата)
const phrase = translate(парамсы) - при это фраза это строка и в себе функцию не содержит, где тогда хранится предыдущее вычисленное значение?
Использую реселект, только когда компонент использует UseSelector - в таком случае удается не перерендеривать компонент использующий UseSelector
Спасибо!
Очень нравятся ваши видео, но если честно пример не очень корректный. Вы ведь не на бэкенде используете реселект с миллиардом операций. Думаю потеря времени на ререндер будет гораздо существенней чем экономя времени на кеширования реселект.
Ps: не уверен что правильно именно так делать бенчмарк, разве у js нет таких понятий как прогрев? Или компиляция часто используемых функций в машинный код, инлайнинг итд.
Все верно про рендер. В рамках этого видео, хотел показать, что мемоизация не бесплатная на реальных цифрах. Да и показать, что иногда кажется, очевидно как работает инструмент, а на самом деле все немного сложнее. Чтобы показать всю историю с рендерами, я записал еще одно видео, показывающее какую именно проблему решает реселект:
th-cam.com/video/tbfo28Q5eag/w-d-xo.html
И собственно сейчас готовлю видео, про сам реселект в рамках React
По поводу измерений, было много комментариев на эту тему, поэтому записал еще одно видео с более точными бенчмарками:
th-cam.com/video/ZVSJckibKe8/w-d-xo.html
Super!
А почему нельзя просто в реакте производить нужные вычисления из под useMemo к примеру. Тогда вы будем использовать только простые селекторые и в них самих ничего делать не будем. Следовательно не будет лишних вызовов из редукса. А лишние пересчеты самого реакта мы отметаем либо useMemo либо ключами при list rendering
Вы все правильно говорите, так и стоит поступать. Есть лишь один момент с селекторами. Иногда нужно рассчитать итоговую сумму товаров, с учетом карзины, скидок и т.д.. И эту итоговую сумму нужно показать в нескольких местах, абсолютно разных компонентах. В таком случае проще держать эту информацию в селекторах и делиться ей между компонентами
у меня только один вопрос, не как не могу понять зачем использовать что то не по назначению, а патом жаловатся на проблемы?) useSelector (СЛОВО selector) не филр, не мутатор, не что то еще а именно selector... что касается удобства, в чем проблема отдельно отфилтровать? или создать хук в катором это делать? (это косательно реакт)
зачаствую нам нужен вычисленный селектор в многих местах. Например totalPrice. Не хочется ее вычислять несколько раз в разных местах. Куда удобнее посчитать 1 раз и в остальных местах отдавать значение из кэша
@@it-sin9k а что мешает в initialState добавить totalPrice? и в редюсере при добавлении в массив price новой цены обновить totalPrice, потому как примая зависимость totalPrice prices
@@armensargsyan8981 От данного подхода давно отказались. У него есть 2 проблемы:
- totalPrice может высчитываться из допустим 5-6 параметров (цены, скидки, время суток и т.д.). В итоге на любой из экшенов обновления любого из полей надо обновлять и totalPrice. А если еще какой-то из полей надо хранить в каком то другом редьюсере, то нужно в экшен еще пробрасывать значение всех нужных полей. В итоге увеличивается шанс, что totalPrice будет не настоящий. Поэтому все и используют вычисляемый селектор, вместо хранения. Чтобы избежать нескольких источников истины и их синхронизации
- 2-ая проблема, это получится, что в reducer будет хранится какая то бизнес логика. А от этого давно вроде все решили избавляться. Не местой бизнес логике в редьюсере
@@it-sin9k можно все это обойти, во первых вынести totalPrice в отдельный reducer (конечно ломается логическая взоимосвяз между prices totalPrice что плохо, но думаю приемлимо, так как он зависит еще и от 5-6 полей которые в других редюсерах), и что то новое но все же(использовать некий вычислительный компонент(watcher) который нечего не рендерит а только диспатчит totalPrice при изменении 5-6 пропсов): по итогу вычисляется только единожды, и все работает как задумано. НО огромное спасибо!!! за обяснение что как, понял смысл селекторов и createSelector-а, еще раз спасибо!
Я тоже не угадал) Спасибо за видео, Саш. Можешь снять про recoilJS? Она еще находится у меты под тегом экспериментального см, но выглядит уж очень любопытно 👀
Да, у меня список на изучение стоит recoil, zustand, effector)) Только обозревать все это не так просто и быстро)
@@it-sin9k понимаю) мало того, что нужно оформить кейс, еще и посмотреть как это устроено внутри)
zustand самый мемный как по мне)
@@it-sin9k но recoil вроде как прям очевидный, у них классное видео на превью странице, которое четко описывает задачу.
Самое интересное, что мне про каждую из технологий, так кто то пишет) что одна технология это такое) а вот другая, намного интереснее)
@@it-sin9k интереснее не значит эффективная) каждая решает какие-то свои задачи, а превью вроде как всегда показывает самые лучшие юз кейсы без случаев когда НЕ стоит её использовать как мы узнали из сегодняшнего видео)
Вердикт: забыть вместе с redux
Этот бенчмарк не отражает действительности из-за оптимизаций v8
Какой-то конкретной оптимизации?
@@it-sin9k th-cam.com/video/HPFARivHJRY/w-d-xo.html
Хорошее видео про оптимизацию и бенчмарки
@@grandphone3585 да, я знаком с подобного рода видео. Они очень поучительны. И конечно я не могу гарантировать, что мои бенчмарки правдивы. Но и говорить, что именно эти бенчмарки не отражают действительность мы тоже не можем.
Далее напрашивается вопрос, а почему же я в итоге решил записать подобного рода видео. Основной мотивацией служили косвенные признаки. Я делал разного рода бенчмарки, и общая динамика отражала, идеи которые заложены в этом коде. Да действительно возможно 99_999_999 выполняются за иное количество времени, чем у меня в видео, но мне тут были важны не абсолютные значения, а скорее общая динамика (быстрее или медленее код выполняется). Поэтому для меня это было убедительным доводом, чтобы записать такого рода видео
@@it-sin9k я не спорю с относительными цифрами. Просто в видео подчеркивается, что все выполняется очень быстро хотя так как функций не имеют сайд эффектов, то v8 их выполнил только несколько раз. А в случае с функциями без мемоизации у него хуже вышло
В целом из ролика следует, что преждевременной оптимизацией заниматься не стоит
А добавь плиз eval(' ') в свои функции, чтобы наверняка отключить оптимизации, и покажи новые числа.
Wtf, а что насчёт лишних ререндоров, я так понял их не будет но только если мы будет возвращать наружу значение которое было взято из createSelector. Эта тема не была поднята в видео но я считаю что это важно.
Все верно :)
Про это будет отдельное видео
Кстати есть также возможность добавить колбек снаружи в useSelector-e вторым параметром, разве это тоже не своего рода мемоизация?
Тот колбек должен отвечать за перерисовку компоненты... А видео больше про оптимизацию селекторов... Хотя тот колбек своего рода тоже оптимизация))
Интересно мнение автора.
@@valentynlugovyi4789 Про useSelector у нас есть отдельное видео, где как раз упоминается второй параметр (th-cam.com/video/SVG-x-4BQic/w-d-xo.html). По факту вы правы, этот колбек нужен именно для упразднения лишних рендеров :)
Лучшие видосы по реакту на русском языке
Спасибо! Мы очень стараемся!)
Данная библиотек необходима для предотвращения лишних ререндоров.
я тоже ее только для этого использую... Т.к при использовании голого UseSelector компонент всегда ререндерится
Если что в useSelector можно предотвратить ререндер сравнением стейтов
@@azad0808, немного не понял. Хотелось бы увидеть example
@@mr.nikita прочитай в официальной доке про 2 аргумент хука, "equalityFn"
@@azad0808 Спасибо. Не знал об этом
не угадал
когда уже эта поделка (редакс) уступит место чему-то более адекватному реальности?)
например чему?)
@@it-sin9k использую эффектор 3+ года в проде, полёт отличный.
жаль что он только в узких кругах знаком и в ещё более узких используется)
@@hihoho1578 Я бы не сказал что уже в узких, много людей писали про него уже мне) поэтому планирую обратить внимание на него)
@@it-sin9k ждём обзор)
@@hihoho1578 Ну вот Ситнику настолько не понравились отдельные проблемы эффектора (практически нельзя уменьшить размер), что даже написал свой Наностор.
вместо new Date лучше использовать performance.now()
А оно в ноде то ли не работало, то ли еще что-то. Я уже не помню точно)
@@it-sin9k он в ноде под perf_hooks.performance находится
@@azad0808 попробую обязательно)