只是为了增加我的两分钱。正如其他人所说,文件结构是无主见的。但是,组件命名不是。他们应该是PascalCase,以便 React 知道您使用的是function、class 还是HTMLelement†。
例如:
class input extends Component {...}
糟糕!为什么?因为 React 不知道你是在尝试使用 input 元素还是基于类的组件。
这就是你会看到 PascalCase 组件的原因:
class Input extends Component {...}
† 有一个例外,您可以使用dot notation。例如,如果您有多个导出并将它们全部导入为 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 文件,因为“索引.js" 包含所有必需的代码)。
缺点:
- 你会有很多小文件夹。
- 编译错误都将包含
index.js 命名法,因此起初可能会有点混淆“index.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>
);
为什么?因为在测试时,函数会在酶中显示为:
<_default />
当您在一个组件中有多个匿名函数时,哪个是哪个!?
<_default />
<_default />
<_default />
-
避免使用冗长的文件(150 行或更少),因为阅读/理解会很痛苦,调试会更痛苦。
通常情况下,我发现大多数组件在经过适当优化后会低于 100 行左右。最坏的情况是我必须创建小的子组件来补充主要组件。但!更容易阅读和调试。
什么更容易阅读:
Example #1(34 行带有补充子组件)
Example #2(318 行)
示例 #1 模拟阅读一本书。将多个页面粘合在一起时会产生易于阅读的体验。与示例 #2 相比,它读起来像一英里长的卷轴,很容易迷路!
-
样式表可以是snake-case 或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} />
结论:创建文件夹结构的方法有很多种,其中包含一些技巧和窍门来保持逻辑流程。只需选择一个最适合您并且不会干扰您旁边工作的人!
换句话说,K.I.S.S === “保持简单,傻瓜!”