Как стать автором
Обновить

Комментарии 15

Однако кое-чего у него не отнять — на нём можно написать большой, функциональный, поддерживаемый и быстрый веб-сайт

Так же, как и с любым другим стейт менеджером. Например с MobX, минимальное кол-во кода и оптимизация из коробки бонусом.
MobX в действии: codesandbox.io/s/ecstatic-cloud-l956n

Все бы хорошо, но где примеры использования хуков?

Совет 2 Используйте reselect там, где происходят многократные вычисления.
Совет 3 Не используйте reselect там, где не происходит вычислений.

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

Тут стоит уточнить, что мемоизация (реселектом или нет не важно) для mapStateToProps нужна всегда, когда вы генерируете что-нибудь новое. Даже если это что-нибудь новое это просто создание простого объекта. Т.е. я бы на месте автора перефразировал слово "вычисления" на что-нибудь другое, чтобы не возникало мыслей, что речь идёт только о тяжёлых вычислениях. Любых, которые создают новый references.


Т.е. селекторы чаще всего и не приносят явным образом никакой производительности. Они приносят её косвенным образом (позволяют избежать ререндеров).


Ну и не помешал бы отдельный блок, как можно заменить все эти фабрики селекторов и подобные штуки на мемоизацию посредством weakMaps. Это может сильно упростить сложную кодовую базу, ибо не нужно напрягаться сборкой мусора

Тут стоит уточнить, что мемоизация (реселектом или нет не важно) для mapStateToProps нужна всегда, когда вы генерируете что-нибудь новое. Даже если это что-нибудь новое это просто создание простого объекта

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

Тут стоит уточнить, что мемоизация (реселектом или нет не важно) для mapStateToProps нужна всегда, когда вы генерируете что-нибудь новое. Даже если это что-нибудь новое это просто создание простого объекта.

Согласен, но я бы даже сказал, что только с новыми объектами в mapStateToProps она и нужна. Разработчики react-redux позаботились о базовых принципах производительности и в случае когда mapStateToProps возвращает примитивы, лишних рендеров не произойдет, потому что будет произведена проверка с целью предотвращения ненужных рендеров. Подробнее из доки react-redux.


Так же, стоить помнить что вызов mapStateToProps происходит очень много раз (любой вызванный action вызывает mapStateToProps подключенных компонентов, подробнее), и стоит хорошенько подумать перед тем как наделять его какой-то логикой. Возможно в момент работы action/reducer имеет смысл передать в store уже максимально готовую структуру данных подготовленную для рендера, а возможно имеет смысл перенести эту логику в сам компонент. Во многих случаях достаточно просто избегать создания новых массивов и объектов в mapStateToProps что бы не создавать потенциально проблемных компонентов.


P.S. Думаю вы это и так понимаете, но на всякий случай проясню эти моменты для тех кто забредет в ветку комментариев.

Ещё стоит отметить что придерживаться этих подходов стоит и в самих React компонентах (с несколько меньшим фанатизмом). useMemo, useCallback, hooks.macro, _.memoize, weakMaps и пр. в помощь. Ну и добавить чтобы люди не писали код типа:


const state = useSelector(rootState => rootState);
const { a, b, ... } = state;

в виду того что это в какой-то степени эквивалентно mapStateToProps st => st;

А можно просто использовать MobX и забыть о проблемах с производительностью, с гигантским количеством лишнего кода и зоопарка вокруг Redux'a навсегда. Все уже есть из коробки.

В умелых руках с redux не должно произойти проблем с производительностью. Ну а в неумелых, возможны проблемы и с mobx. А еще стоит помнить что redux весит 7кб, в то время как mobx 55кб (ну если быть честным то связка react-redux + redux весит 21, что все равно в 2 раза меньше). Я не сторонник не mobx, не redux, но на мой взгляд можно выявить недостатки и преимущества в обоих случаях.

— Mobx весит 15kb gziped + mobx-react-lite 1.5kb gziped, webpack-bundle-analyzer в помощь.
— Вес приложения обычно переваливает за 400kb gziped.
— Учитывая то, что с redux надо писать в разы больше коды и это не преувеличение к великому сожалению, это факт. Размер этого оверхеда тупо по коду будет больше чем вес mobx'a.
— Колосальное преимущество в удобстве написания кода, простоты, читаемости кода, скорости написания и дальнейшей поддержки и развития в связке с mobx вообще ни капельки не сравнимо с тем, что даже если бы реально на выходе мы имели бандл слегка пожирнее, но по факту это не так.
— Там, где реально важен максимально легковесный бандл лучше обратится к Svelte.

Вот честно, я не вижу в mobx ни одного не достатка от слова совсем. Он раскрывает потенциал React'a на все 100%.
Какие недостатки вы ведите в mobx'e?
Как вы решаете проблему, что каждый action обрабатывается каждым reducer? На нашем проекте с примерно 200 actions и 200 reducers из за тормозов пришлось отказаться от redux в пользу альтернатив. Хочется понять, мы что-то не так делали или redux действительно не заточен на это?
В пользу каких альтернатив?

Признаться не упирались в такое. Выпадет свободная минута — попробую побэнчить это дело. Умозрительно контейнеры выглядят даже большей проблемой — их точно больше 200 на странице, и каждый со своим mapStateToProps и возможностью перерисовать часть дерева под собой.


Сейчас глянул на одной из тяжелых страниц: около 100ни коллекций, редюсеров на вскидку 50-70. Возможно, дело в том, что мы очень сильно нормализуем данные. Вложенных структур почти не встречается в стейте: всё плоское и связано через айдишники. Следовательно, не получается и глубокой вложенности редюсеров. Они выходят очень точечными и работают на крайне небольшое количество экшенов. Как следствие, отрабатывают мгновенно: быстро понимают, что экшн не про них, и отдают текущий кусок стейта. Самый толстый редюсер (по памяти) штук 10 экшенов обрабатывает.

Мы решаем это тем (на самом деле не это решаем, ну да ладно), что отказались от рекомендуемой практики pub-sub, в сторону нерекомендуемой практики паттерна "Команда". В action.type зашит путь к его личному reducer-у, и он всегда один и только один. Это частично режет крылья в одних случаях, но зато упрощает систему в других. Рекомендую такой подход тем, у кого не сильно связанные с друг другом сущности и хочется больше порядка и очевидности. Но да, минздрав такое не рекомендует.

200 actions и 200 reducers из за тормозов пришлось отказаться от redux в пользу альтернатив

А вообще я рекомендую вам попрофилировать ваше приложение ещё разок. Такие масштабы не должны вызывать хоть сколько-нибудь ощутимых тормозов. Скорее всего они у вас совсем в другом месте.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории