Просто, чтобы добавить мои два цента.Как уже говорили другие, файловая структура не установлена.Однако именования компонентов нет.Они должны быть PascalCase
, чтобы React узнала, используете ли вы function
, class
или HTML element
†.
Например:
class input extends Component {...}
Плохо !Зачем?Потому что React не знает, пытаетесь ли вы использовать элемент input
или компонент на основе классов.
Вот почему вы увидите компоненты PascalCase:
class Input extends Component {...}
† Есть одно исключение, где вы можете использовать dot notation
.Например, если у вас было несколько экспортов, и вы импортировали их все как fields
, то вы могли бы сделать что-то вроде:
component / fields / index.js
import React, { Component } from 'react';
export class input extends Component {
state = { value: "" };
handleChange = ({ target: { value } }) => {
this.setState({ value });
};
render = () => (
<input type="text" value={this.state.value} onChange={this.handleChange} />
);
}
export class textarea extends Component {
state = { value: "" };
handleChange = ({ target: { value } }) => {
this.setState({ value });
};
render = () => (
<textarea
type="text"
value={this.state.value}
onChange={this.handleChange}
/>
);
}
components / App / index.js
import React, { Fragment } from 'react';
import * as fields from "../fields";
const App = () => (
<Fragment>
<fields.input />
<fields.textarea />
<Fragment>
);
export default App;
Как правило, я вообще избегаю dot notation
.Это кажется неуклюжим и может запутать других разработчиков, которые не знают, как структурирована fields
.Кроме того, я не люблю складывать несколько компонентов в один файл, а затем импортировать их в виде набора.Кроме того, файл может стать довольно большим и громоздким для навигации и отладки (подробнее об этом ниже).
Тем не менее, чтобы упростить мою структуру, мне нравится сохранять основные каталоги строчными:
├── dist // compiled application files to be served
| ├── css
| | ├── main.[contenthash:8].css
| | └── main.[contenthash:8].css.map
| ├── js
| | ├── main.[hash].js // depending on app size, this may contain multiple js files for code splitting
| | └── main.[hash].js.map
| ├── media
| | └── [hash].[ext] // static assets like fonts and images
| └── favicon.ico
| └── index.html
|
├── config // supporting "webpackdevserver" configuration files
| ├── devServer.js
| ├── envs.js
| ├── optimization.js
| ├── output.js
| ├── paths.js
| ├── plugins.js
| └── rules.js
|
├── public
| ├── favicon.ico
| └── index.html
|
├── src
| ├── actions // redux actions
| ├── components // stateful and stateless reusable components that just display "stuff" -- stateful components change and manipulate the UI
| ├── containers // stateful components that utilize the reusable "components" to CRUD data and/or are connected to redux
| ├── images
| ├── pages // utilize components/containers to display something when visiting a "/route"
| ├── reducers // redux reducers
| ├── root // aka "<App />" that combines "routes", redux and other top-level supporting files into one place
| ├── routes // assigns "pages" to a "/route"
| ├── styles // shared and/or global styles used by all "components"
| ├── types // redux types
| ├── utils // supporting app files: like test setup, custom polyfills, axios configurations, ...etc
| └── index.js // a simple file that "ReactDOM.render"s the "App"
|
├── server.js // express setup to serve the "dist" folder
└── webpack.config.js
Затем в папке component
я буду PascalCase, чтобы мои компоненты представляли что-то вроде этого:
└── components
└── Input
├── __tests__
| └── Input.test.js // jest unit tests for "index.js"
├── index.js // all required code/styles to be exported
└── styles.scss // styles required by "index.js"
Почему эта структура?
- Многократно используемые компоненты, которые можно использовать везде и всегда.
- Все, что связано с
Input
, находится внутри этой папки.Поэтому я могу передать его кому-то, и они могут вставить его в свое приложение и просто использовать его. - Webpack настроен на автоматический импорт
index.js
, поэтому его очень легко импортировать, не пересекая тоннувложенных файлов: import Input from 'components/Input';
(также нет необходимости указывать точный js
файл для использования, поскольку «index.js» содержит весь необходимый код).
Недостатки:
- У вас будет много маленьких папок.
- Все ошибки компиляции будут содержать номенклатуру
index.js
, так что поначалу может показаться немного запутанным, какой индекс.js "не удалось.
Другой подход, который я использовал, был:
└── components
├── input // lowercase name to delineate it's a "pure" function -- the actual function will be a PascalCased "Input"
| ├── input.test.js // jest unit tests for "input.js"
| ├── input.js // all required code/styles to be exported
| └── styles.scss // styles required by "input.js"
|
└── Sidebar // PascalCase because it's a "class"
├── Sidebar.test.js // jest unit tests for "Sidebar.js"
├── Sidebar.js // all required code/styles to be exported
└── styles.scss // styles required by "Sidebar.js"
Почему эта структура?
- Многократно используемые компоненты, которые можно использовать везде и всегда.
- Все, что связано с
Input
, содержится внутри этой папки.Поэтому я могу передать его кому-то, и они могут вставить его в свое приложение и просто использовать его. - В зависимости от основной папки, он определяет, является ли компонент
function
или class
. - Когда возникает ошибка компиляции, я точно знаю, какой файл вызвал ошибку.
Недостатки:
- Вы будетеУ меня много маленьких папок.
- Иногда компонент может измениться с состояния на состояние без состояния (или наоборот), поэтому, если вы строгие и придерживаетесь этого шаблона именования, вам придется обновить основнойпапка, чтобы отразить изменение, что означает, что вам также необходимо обновить путь для любых других файлов, которые используют это.
- Импорт может выглядеть немного избыточным и длинным:
import Input from 'components/input/input.js';
Другие общие рекомендации:
- Избегайте экспорта по умолчанию анонимной функции :
Пример экспортированной по умолчанию анонимной функции:
export default () => (
<p>Anonymous Function</p>
);
Почему?Потому что при тестировании функция будет отображаться в Jest как:
<_default />
Когда у вас есть несколько анонимных функций в компоненте, какая из которых есть??
<_default />
<_default />
<_default />
- Избегайте длинных файлов (150 строк или меньше), так как становится труднее читать / понимать и еще больше труднее отлаживать.
Чаще всего я обнаружил, что большинство компонентов упадут до 100 строк или около того при правильной оптимизации.В худшем случае мне придется создать небольшие подкомпоненты, чтобы дополнить основной компонент.Но!Гораздо проще читать и отлаживать.
Что легче читать:
Пример # 1 (34 строки с дополнительными дочерними компонентами)
Пример # 2 (318 строк всего)
Пример # 1 имитирует чтение книги.Несколько страниц, которые при склеивании создают легкий для чтения опыт.По сравнению с примером № 2, который читает как свиток длиной в милю, в котором легко потеряться!
- Таблицы стилей могут быть в виде змеи или camelCase.
Это может сбивать с толку, но все зависит от того, как вы применяете стили,Если вы просто импортируете стиль следующим образом:
import "./styles.css";
Тогда вы можете использовать случай со змеей:
<input className="snake-case" type="text" value="" onChange={this.handleChange} />
Однако, если вы используете css modules
, то выВам нужно будет использовать camelCase:
import { camelCaseClassName } from "./styles.css";
Почему?Поскольку упаковщики (например, Webpack) не поддерживают импорт в случае со змеями:
<input className={camelCaseClassName} type="text" value="" onChange={this.handleChange} />
Заключение: Существует много способов создания структуры папок с несколькими советами и рекомендациями для поддержания логического потока.Просто выберите тот, который работает лучше для вас и не мешает человеку, работающему рядом с вами!
Другими словами, ПОЦЕЛУЙ === "Говори просто, глупо!"