Русский
Русский
English
Статистика
Реклама

Из песочницы Архитектура приложения React Redux

Предисловие


Это мой первый пост на Хабре, поэтому не судите сильно строго (ну или судите, но конструктивно).

Хотелось бы отметить, что в этом подходе основным преимуществом для меня стало то, что мы четко разграничиваем и делегируем бизнес логику по модулям. Один модуль отвечает за что-то одно и за что-то весьма конкретное. То есть, при таком подходе, в процессе разработки не возникает мысли: а где мне лучше (правильнее) будет сделать вот это вот?. При таком подходе сразу ясно, где конкретно должна решаться задача/проблема

Файловая структура


Структура проекта +- стандартная. Попытаюсь рассказать вкратце, что используется из чего состоит непосредственно сборка



  • Для готовки асинхронных экшнов я использую saga middleware куда более гибкая и сильная вещь, относительно thunk middleware
  • Стилизацией компонентов у меня занимаются css-modules. По сути концепция та же, что и у styled components, но мне как-то оно удобнее
  • Прослойкой между контейнерами и компонентами, которая контролирует прокидываемые из стора пропсы в компонент (фильтрация, мемоизация и возможность удобного манипулирования над именами полей любого куска состояния приложения) reselect

Redux sagas


Redux sagas documentation

Основная суть саг (да и не только) мы отделяем бизнес логику работы с запросами по модулям. Каждая сага отвечает за свой кусок АПИ. Если бы мне понадобилось получить данные о юзере и вызвать экшн по их успешному получению я бы это сделал в отдельном модуле usersSagas.js

Основной фактор (для меня) в пользу саг это то, что экшны, по-хорошему должны быть просто функциями, отдающими объект. Если часть экшнов будет выглядеть по-другому (а с использованием thunk оно так и происходит), хочется как-то привести их к оджному виду, ибо как-то это не укладывается в единую концепцию. Хочется вынести логику запросов и работы с данными для запросов в отдельный модуль для этого и нужны саги



css-modules/styled components


Часто вижу на проектах, что люди пишут правила для стилизации компонентов в каких-то общих модулях css.

Я категорически против этого. Компонент изолированная система. Он должен быть максимально переиспользуемым. Поэтому, хорошо бы его и стилизовать отдельно.





Reselect


Selectorы преследуют несколько целей:

  • Вынесение логики работы с данными, приходящими в комопнент в отдельный модуль. Это, когда нам нужно получить как бы отфильтрованные данные, но мы не хотим заводить под это кусок стора (это здорово, если мы НЕ хотим заводить отдельный кусок стора под это). До того, как я начал использовать реселект, я делал это внутри компонента. Делал какой-нибудь метод getFilteredItems, в котором возвращал отфильтрованные данные
  • Мемоизация и контроль над пропсами, которые будут контролить ререндер компонента
  • Гибкость рисунка дерева состояния. К примеру у нас приходят какие-то данные с бека по юзеру. Нам в компоненте нужно получить только какой-то кусок этих данных. К примеру это будет массив friends. Мы пишем селектор под друзей и в контейнерах, которые используют этот кусок стейта его импортируем. Если бы мы не использовали селектор, то мы бы ручками писали название этого поля в каждом контейнере. Представим ситуацию, что логика приложения поменялась, и поле friends переименовали на contacts. Без использования reselect мы будем лазить по всем контейнерам, так или иначе использующими это поле, и менять его название. С использованием реселекта поменяем парочку реселектов.

Именно из-за последнего пункта я топлю за то, что мы делаем реселект на каждый чих. Реселект не только для мемоизации, но и для более удобной работы с рисунком дерева состояния приложения



Components and Containers


В классическом подходе к React'у (без использования библиотек для хранения стора, как отдельной сущности) есть два вида компонентов Presentational и Container-Components. Обычно (как я это понимаю) это не строгое разделение по папкам, а скорее концептуальное разделение.

Presentational глупые компоненты. Они представляют из себя, по сути, только верстку и отображение данных, которые в них прокинули в качестве пропсов. (пример такого компонента можно глянуть выше в css-modules)

Container-Components компоненты, инкапсулирующие логику работы с, к примеру, лайф-сайклом компонента. Они отвечают за вызов экшна, отвечающего за запрос на получение данных, к примеру. Возвращают минимум верстки, ибо верстка изолирована в Presentational-Components.

Пример +- Container-Component:



Redux Containers это, по сути, прослойка между стором редакс и компонентами реакта. В них мы вызываем селекторы и прокидываем экшны в пропсы реакт компонента.

Я ЗА то, чтобы на каждый чих иметь свой контейнер. Во-первых это дает бОльший контроль над пропсами, прокинутыми в компонент, во-вторых контроль над производительностью, с помощью реселекта.

Часто бывает так, что нам нужно переиспользовать один компонент, но с разными кусками стора. Получается, что для этого нам просто нужно будет написать еще один контейнер и вернуть его там, где необходимо. То есть, связь Многие к одному (многие контейнеры, один компонент. По мне удобно и концептуальненько)

Также хотелось бы привести более частый пример в пользу контейниризации большинства компонентов.

У нас есть массив данных (массив юзеров, к примеру), который мы получаем с некоторой АПИ. Также у нас есть инфинит скролл, от которого заказчик не собирается отказываться. Мы очень долго листали вниз и подгрузили около 10к+ данных. А теперь мы поменяли какое-то свойство одного юзера. Наше приложение будет сильно тормозить, потому что:

  1. Мы прикрутили глобальный контейнер на всю страницу со списком юзеров
  2. При изменении одного поля одного элемента массива users у нас в редьюсере users вернулся НОВЙ массив с новыми элементами и индексами
  3. Все компоненты, размещенные в дереве компонента UsersPage будут перерисовываться. В том числе и каждый компонент User (элемент массива)

Как этого избежать?

Мы делаем контейнера на

  • массив с юзерами
  • элемент массива (один юзер)

После этого мы в компоненте, который завернут в контейнер массив с юзерами возвращаем контейнер элемент массива (один юзер) с прокинутыми туда key (react required prop), index

В контейнере элемент массива (один юзер) в mapStateToProps мы вторым аргументом принимаем ownProps компонента, который контейнер возвращает (среди них index). По индексу мы вытаскиваем из стора напрямую только один элемент массива.

Дальше заоптимизировать перерисовку только изменившегося элемента станет гораздо проще (перерисовывается весь массив, потому что в редьюсере мы сделали какой-нибудь map возвращающий НОВЙ массив с новыми индексами под каждый элемент) тут нам уже поможет reselect

массив container:



элемент container:



element-selector:



Если есть какие-то дополнения с удовольствием их почитаю в комментах.
Источник: habr.com
К списку статей
Опубликовано: 19.08.2020 02:13:55
0

Сейчас читают

Комментариев (0)
Имя
Электронная почта

Reactjs

React redux

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru