В отличии от предыдущей структуры где редукс код держался отдельно от реакта, но групировался по назначению в двух разных местах в этом подходе мы стуктурируем код по назначению используя atomic & redux ducks под одной папкой. Пример:
Ui/
atoms/
Button/
Icon/
Shadow/
molecules/
ErrorPage/
index.js
ErrorPage.jsx
organisms/
SearchBar/
templates/
InfoTemplate
User/
atoms/
UserAvatar
molecules/
UserSelection
organisms/
UserTable
pages/
UserPage
reducers/
entities
pagination
uistates
selectors/
selectUsersArray
selectFilteredUsers
services/
userValidation
userApi
utils
Article/
//...same as for user module
atoms/
molecules
reducers
selectors
servies
services
apiService // abstract api
commonUtils
App/ - common hocs, components, redux setup and other common stuff
Ui - эта папка представляет собой юай кит для проекта, на начальном этапе разработки смысла выносить юайкит в отдельный проект нету, но есть смысл отделить его от основного кода и переиспользовать в разных модулях. В этой папке находится все общее застайленные компоненты. Т.е кнопки, тулбары, поповеры, селекты и тд все юайные компоненты которые надо переиспользовать стоит положить в эту папку.
App - эта папка нужна для сборки всех модулей в одно целое, тут находится сетап для редукса для темы проекта и прочий стафф, так же сюда можно положить общие хоки и контейнеры, но по мере их увеличения их можно выделить в отдельный модуль. Так же тут можно использовать такую же структуру как и в модуле. Т.е по сути Апп это просто основной модуль
Article/User - Это модули нашего приложения, структура модуля выглядит как атомик + reducers/selectors/services но эти папки можно варировать. Основой идеей такого подохода, что в этой папке лежит по максимуму ничего лишнего.
Если модуль становится слишком большим, то имеет смысл создать вложенный модуль и по максимуму изолировать его от родительского. Но сильно вкладывать модули друг в друга не стоит, лучше придерживаться flat структуры и если можно вынести что-то в модуль, то не вкладывать его в другой модуль, а положить рядом.
Если имеются 2 сильносвязанных модуля, код которых тяжело разделять, то можно применить подоход, что выделяем основной модуль и пытаемся вынести в него большую часть логики, которая как-то с ним связана а другой модуль, оставляем только для компонентов.
services в корне - иногда имеет смысл не разделять апи провайдер приложения или логику валидации на модули, а оставить ее в корне приложения, то тогда такой код лучше всего положить в папку services в корне.
- Разделяем юайкит приложения и верстку специфическую под какуе-то фичу
- Делаем правильную декомпозицию приложения и пытаемся выделить отдельные части модуля
- Делаем публичное апи модулей под одним интерфейсом, а так же как можно меньше (Более простое апи модуля будет проще поддерживать и легче будет вести паралельную разработку)
- В модуле пытаемся делать связи только на код модуля и не завязываться на глобальный стейт приложения (вместо использования глобального редюсера для екшинов, форм и ошибок используем локальные редюсеры для таких потребностей)
- Пытаемся делать перемычки между модулями в 1-2 местах т.е если модуль А использует что-то из модуля Б, то модуль А должен в корне модуля заимпортить нужные данные, а дальше опираться уже на заимпорченные данные.
- Перемычки между модулем и App должны быть в 1 месте, что бы можно было его легко убрать или спрятать.
- Поключение зависимостей модуля, которые затрагивают глобальный стейт или меняют что-то в приложении после импорта этого модуля должны считаться как асинхронные, даже если они синхронно работают