Я был немного одержим оптимизацией структуры папок и иерархии компонентов моих приложений React и, наконец, пришел к решению, которым я вполне доволен.
Компонент Ответственность
Всякий раз, когда я создаю или изменяю Компонент, я постоянно оцениваю и переоцениваю его ответственность. Вот некоторые из них:
- Управлять внутренним состоянием
- Предоставление методов жизненного цикла компонентов
- Подключитесь к хранилищу Redux (или аналогичной библиотеке управления состоянием)
- Рендер jsx
Обычной практикой является включение кода для двух или более из этих обязанностей в один компонент. Основные проблемы с этим подходом заключаются в том, что его сложнее тестировать, отлаживать и проверять код, чем компонент, который выполняет только одну из этих обязанностей.
Это адаптация принципа единой ответственности.
Если вы еще этого не сделали, прочитайте эту статью Дэна Абромова о компонентах Presentational и Container. Он делает фантастическую и краткую работу по объяснению этих концепций лучше, чем я когда-либо мог :)
Большинство идей в этой статье — это всего лишь итерации этих фундаментальных идей, представленных Дэном.
Стоит отметить, что хотя я могу упомянуть Redux в этой статье, представленные здесь принципы не относятся к какой-либо одной библиотеке управления состоянием. Эти идеи можно адаптировать для MobX, Apollo Client или просто Context API. Я всегда думал, что самая мощная часть Redux — это не сама библиотека, а идея разделения задач вашего приложения на простые компоненты.
Слои компонентов
Я очень не люблю классовые компоненты в React. Основными причинами выбора компонента класса вместо функционального компонента являются (1) управление внутренним состоянием или (2) доступ к методам жизненного цикла компонента.
Если вы хотите, чтобы ваш компонент имел эту дополнительную функциональность, вам следует использовать компонент класса, но, на мой взгляд, это нарушает принцип единой ответственности.
В качестве альтернативы я предпочитаю всегда использовать функциональные компоненты для рендеринга jsx и предоставлять дополнительные функции в отдельных компонентах.
Сгруппированные слои компонентов
Допустим, вы создаете поле ввода формы. Если вы следуете принципу единой ответственности компонентов, вы можете получить иерархию компонентов, показанную здесь:
...
Input
InputContainer
InputWithState
InputPresenter
...
InputPresenter
— Рендерим JSX и отвечаем на пользовательские событияInputWithState
— Используйте Recompose withStateHandlers для предоставления локального состояния и методов обновления состояния.InputContainer
— Подключитесь к магазину Redux и предоставьте создателям действий ReduxInput
— Компонент-оболочка для более стабильного тестирования презентационных компонентов более высокого уровня.
Структура файла
К счастью для нас, создатели React наконец-то определились с лучшей файловой структурой для реактивных проектов!
Я думаю, что этот подход отлично работает для отдельных лиц и небольших команд, но для больших команд может быть неплохо иметь немного более строгий шаблон структуры папок.
Мне нравится организовывать файловую структуру моего компонента в соответствии с пользовательским интерфейсом приложения. Например:
components
│
└───InputParent
│ └── InputParentPresenter.js
│ └── ...
│ │
│ └── children
│ │
│ └── Input
│ └── index.js
│ └── InputContainer.js
│ └── InputWithState.js
│ └── InputPresenter.js
│ │
│ └── tests
│ │ └── InputContainer.spec.js
│ │ └── InputWithState.spec.js
│ │ └── InputPresenter.spec.js
│ │
│ └── children
│ │
... └── ...
Альтернативным подходом к этому было бы хранение всех компонентов в плоской папке. Я предпочитаю вложенный подход, потому что мне легче ориентироваться и он более масштабируем для сложных приложений.
У этого подхода есть несколько недостатков, но есть простые обходные пути:
- Сложно поделиться компонентами → Создайте общую папку в папке
/components
- Импорт в глубоко вложенные компоненты → Используйте псевдонимы webpack для часто используемых папок
Чтобы упростить создание этих компонентов, я сделал генератор строительных лесов Yeoman под названием mnml-component.
Вывод
Следование этому подходу упростило мне разработку и масштабирование приложений React. Пожалуйста, дайте мне знать в комментариях, если у вас есть какие-либо отзывы об этом подходе или инструменте mnml-component!