javascript

Организация компонентов в React проекте

  • понедельник, 10 апреля 2017 г. в 03:15:04
https://habrahabr.ru/post/326018/
  • Разработка веб-сайтов
  • ReactJS
  • JavaScript


Многие руководствуются рекомендациями Presentational and Container Components, но уважаемый автор признаётся в сносках, что концепция разделения спорная, и компоненты можно смешивать. А если это так, то зачем тащить чемодан без ручки? Все компоненты проекта удобнее хранить в одной общей папке. Какие плюсы:
  • Простота навигации по файловой системе.
  • Уникальные имена компонентов проекта.
  • Импорт без боли ('../../../../../..').


Когда проект вырастет, следует дробить его на приватные npm-пакеты, инкапсулируя реализацию. Но не выращивать дерево подпапок внутри папки компонентов — развивать и поддерживать такое ощутимо сложнее. Проверено.

Все компоненты организованы по доменному принципу в одной папке src/componens. Например, можно определить домены: Post — отображение публикации, PostForm — форма редактирования публикации.


Как создать доменный компонент — src/components/Post/Post.js.


Почему нельзя использовать index.js вместо Post.js — соблюдается уникальность имен файлов компонентов внутри проекта, так упрощается навигация по вкладкам редактора (и в WebStorm будет работать ценная функция "Find Usages" для контекстного меню выделенного файла — см. примечание).


Все компоненты в папке доменного компонента получают префикс доменного компонента (Post*.js).


Подпапки в папке доменного компонента не допускаются, внутри плоская структура файлов из компонентов-потомков (PostTitle.js, PostBody.js) и компонентов-предков (PostViewPage.js, PostListPage.js). Компоненты-потомки используются внутри доменного компонента, а компоненты-предки используются снаружи (в роутере).


Чтобы инкапсулировать импорт доменных компонентов, следует задать внутри каждой папки доменного компонента свой package.json, в котором прописать точку входа "main":


{
  "name": "Post",
  "version": "0.0.0",
  "private": true,
  "main": "./Post.js",
}

Кроме того, внутри файла доменного компонента (Post.js) объявлен реэкспорт компонентов-предков:


import PostViewPage from './PostViewPage'
import PostListPage from './PostListPage'
//...
export { PostViewPage, PostListPage }
export default Post

К сожалению, нельзя использовать конструкцию "export from" (ограничение WebStorm), например:


export { default as PostViewPage } from './PostViewPage'

В результате не требуется явного доступа к файлам внутри папки компонентов, например:


import Post from 'components/Post/Post'

По соглашению, разрешается использовать импорт только по доменному имени компонента:


import Post, { PostViewPage, PostListPage } from 'components/Post'

Исходники


Примечание по функции "Find Usages" в WebStorm. Как минимум, есть три контекста использования: 1) по выделенному файлу, 2) по выделенной переменной или символу, 3) по выделенному default в экспорте компонента.


1) Выделим файл components/Post/PostViewPage.js, результат поиска:


// Post.js
import PostViewPage from './PostViewPage'

2) Выделим символ PostViewPage внутри файла PostViewPage.js, результат поиска:


// PostViewPage.js
PostViewPage.propTypes = {}

3) Выделим default в экспорте компонента PostViewPage, результат поиска:


// routes.js
import { PostViewPage } from 'components/Post'
<Route exact path="/post/:id(\d+)/" component={PostViewPage} />

Как видно, третий способ использования выдает наиболее полезную информацию для компонента-предка.


PS


CSS внутри компонентов

Найден правильный способ прикрутить Styled-JSX для Create React App. Теперь CSS-блоки живут внутри файлов компонентов естественным для себя образом — в CSS-формате (против инлайн-стилей JS-объектов). И не нужно беспокоиться за глобальную область видимости.


Абсолютные пути в импорте

Работают относительно папки src, благодаря babel-plugin-module-resolver:


import MyComponent from 'components/MyComponent'

Настройка WebStorm

Для папки src в контекстом меню выполнить: Mark Directory as > Resource Root.


Настройка Atom

  • Установить плагин js-hyperclick.
  • Для доменных компонентов прописывать в package.json путь до src:
    {
    "moduleRoots": [
    "../.."
    }