1.基本规则
• 一个文件声明一个组件: 尽管可以在一个文件中声明多个 React 组件,但是最好不要这样做;推荐一个文件声明一个 React 组件,并只导出一个组件;
• 使用 JSX 表达式: 不要使用 React.createElement 的写法;
• react 18尽量使用函数组件。
2.命名规范
• 扩展名: 用 .tsx
作为组件扩展名。
• 文件名: 用大驼峰作为文件名,如:ReservationCard.tsx
。
• 参数命名: React 组件用大驼峰,组件的实例用小驼峰。eslint: [react/jsx-pascal-case](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-pascal-case.md)
// bad
import reservationCard from './ReservationCard';
// good
import ReservationCard from './ReservationCard';
// bad
const ReservationItem = <ReservationCard />;
// good
const reservationItem = <ReservationCard />;
• 组件命名: 文件名作为组件名。例如:ReservationCard.jsx 应该用 ReservationCard 作为参数名。 然而,对于一个文件夹里的跟组件,应该用 index.jsx 作为文件名,同时用文件夹名作为组件名
// bad
import Footer from './Footer/Footer';
// bad
import Footer from './Footer/index';
// good
import Footer from './Footer';
• 高阶组件HOC命名: 用高阶组件名和传入的组件名组合作为生成的组件的 displayName。 举个例子,一个高阶组件 withFoo(), 当传入一个组件 Bar 应该生成一个新的组件,他的 displayName 属性是 withFoo(Bar)。
Why? 组件的 displayName 可以用于开发者工具或者错误信息中,同时还有一个值可以清晰的表达这种组件关系,这可以帮助人们理解到底发生了什么
// bad
export default function withFoo(WrappedComponent) {
return function WithFoo(props) {
return <WrappedComponent {...props} foo />;
}
}
// good
export default function withFoo(WrappedComponent) {
function WithFoo(props) {
return <WrappedComponent {...props} foo />;
}
const wrappedComponentName = WrappedComponent.displayName
|| WrappedComponent.name
|| 'Component';
WithFoo.displayName = `withFoo(${wrappedComponentName})`;
return WithFoo;
}
• Props 命名: 避免用 DOM 组件的属性名表达不同的意义
Why? 人们期望 style、 className 这种属性代表一个明确的意义。 为应用程序的一个子集改变此API会使代码的可读性降低,维护性降低,并可能导致错误。
// bad
<MyComponent style="fancy" />
// bad
<MyComponent className="fancy" />
// good
<MyComponent variant="fancy" />
3.对齐
对 JSX 语法使用这些对齐风格。 eslint: react/jsx-closing-bracket-location react/jsx-closing-tag-location
// bad
<Foo superLongParam="bar"
anotherSuperLongParam="baz" />
// good
<Foo
superLongParam="bar"
anotherSuperLongParam="baz"
/>
// 如果能放在一行,也可以用单行表示
<Foo bar="bar" />
// Foo 里面的标签正常缩进
<Foo
superLongParam="bar"
anotherSuperLongParam="baz"
>
<Quux />
</Foo>
// bad
{showButton &&
<Button />
}
// bad
{
showButton &&
<Button />
}
// good
{showButton && (
<Button />
)}
// good
{showButton && <Button />}
4.引用
在 JSX 属性中用双引号("),但是在js里用单引号(')。eslint: jsx-quotes
Why? 正常的 HTML 属性也通常使用双引号而不是单引号,所以 JSX 属性也使用这个约定。
// bad
<Foo bar='bar' />
// good
<Foo bar="bar" />
// bad
<Foo style={{ left: "20px" }} />
// good
<Foo style={{ left: '20px' }} />
5.属性
props 用小驼峰
// bad
<Foo
UserName="hello"
phone_number={12345678}
/>
// good
<Foo
userName="hello"
phoneNumber={12345678}
/>
如果 prop 的值是 true 可以忽略这个值,直接写 prop 名就可以。 eslint: react/jsx-boolean-value
// bad
<Foo
hidden={true}
/>
// good
<Foo
hidden
/>
// good
<Foo hidden />
避免用数组下标作为 key 属性,推荐用稳定的 ID
Why? 不使用稳定杆的 ID is an anti-pattern 会对组件性能产生消极影响,并且组件状态容易出现问题。 如果数组元素可能会发生变化,我们不推荐使用下标作为key。
// bad
{todos.map((todo, index) =>
<Todo
{...todo}
key={index}
/>
)}
// good
{todos.map(todo => (
<Todo
{...todo}
key={todo.id}
/>
))}
6.关于Refs 请勿过度使用
详见react官方文档Refs and the DOM
Refs 转发
7.Hook 规则
只在最顶层使用 Hook
不要在循环,条件或嵌套函数中调用 Hook, 确保总是在你的 React 函数的最顶层调用他们。遵守这条规则,你就能确保 Hook 在每一次渲染中都按照同样的顺序被调用。这让 React 能够在多次的 useState 和 useEffect 调用之间保持 hook 状态的正确。(如果你对此感到好奇,我们在下面会有更深入的解释。)
只在 React 函数中调用 Hook
不要在普通的 JavaScript 函数中调用 Hook。你可以:
✅ 在 React 的函数组件中调用 Hook
✅ 在自定义 Hook 中调用其他 Hook
遵循此规则,确保组件的状态逻辑在代码中清晰可见。
8.状态管理规范
约定:
- 当我们项目中复杂程度较低时,建议只用state就可以了
- 如果仅仅因为存在多层传递数据的场景,不建议使用mobx或redux,可使用context解决
- 如果仅仅因为夸路由数据共享,不建议使用mobx或redux,可使用context或者路由传参解决
- 如果业务复杂,需要使用第三方状态管理解决复杂度,看下一条
- 当项目复杂度一般,小规模团队或开发周期较短、要求快速上线时,推荐使用mobx
- 当项目复杂度较高,团队规模较大或要求对事件分发处理可监控可回溯时,推荐使用redux,可尝试使用 rematch或@reduxjs/toolkit,减少模板代码
- 如果后端数据符合REST风格且数据格式统一且重复数据较多,推荐使用扁平化处理数据,参考normalizr,eg: twitter 知乎
9.目录结构
├─package-lock.json
├─package.json ------------ // 项目配置
├─postcss.config.js ------- // postcss 配置
├─public ------------------ // 公开目录
│ ├─favicon.ico
│ └─index.html
├─README.md ---------- // 项目说明
└─src --------------------- // 源码目录
├─App.tsx --------------- // 根组件
├─assets ---------------- // 静态资源目录
│ └─images -------------- // 图片目录
│ └─logo.png ------ // logo 图片
│ └─svg -------------- // 图标目录
│ └─logo.svg ------ // logo 图片
├─components ------------ // 公共组件目录
│ └─Menu ---------------- // 公共组件
│ ├─index.tsx ---------- // 组件文件
│ └─index.scss ------ // 组件样式
├─constants ---------------- // 项目常量
│ └─index.ts
├─libs ------------------ // 第三方库目录
├─index.tsx --------------- // 主入口
├─router ---------------- // 路由配置
│ └─index.tsx
├─store ----------------- // 状态管理
│ ├─module.ts // 模块
│ └─index.ts // 入口
├─tests ----------------- // 测试目录
├─utils ----------------- // 工具目录
│ ├─a.ts
│ └─index.ts
└─pages ----------------- // 视图目录
└─Home ---------------- // 页面组件
├─components -------- // 子组件目录
│ └─Header
│ ├─index.tsx
│ └─index.scss
└─index.tsx ---------- // 组件主体
10.一切尽量遵循官方文档
状态提升 - 多个组件数据变化(遵循原则:依靠自上而下的数据流,而不是尝试在不同组件间同步 state)
React哲学
Effect使用注意
参考
https://jdf2e.github.io/jdc_f...
https://zh-hans.reactjs.org/d...
https://juejin.cn/post/702392...
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。