>[info]参考:《React设计模式与最佳实践》   React官方文档   [React/JSX 编码规范-简书](https://www.jianshu.com/p/2d1c0db6dddb)
[TOC]
以下也可以说是 JSX 语法的规范
# 1. 基本规范
* 每个文件只写一个模块
* 但是多个无状态模块可以放在单个文件中. eslint: react/no-multi-comp
* 推荐使用 JSX 语法
* 不要使用`React.createElement`,除非从一个非 JSX 的文件中初始化你的 app
# 2. 创建模块
* 如果你的模块有内部状态或者是 refs, 推荐使用 class extends React.Component 而不是 React.createClass,也就是说推荐使用 ES6 语法创建 component
```js
// bad
const Listing = React.createClass({
// ...
render() {
return <div>{this.state.hello}</div>
}
});
// good
class Listing extends React.Component {
// ...
render() {
return <div>{this.state.hello}</div>
}
}
// bad (relying on function name inference is discouraged)
const Listing = ({ hello }) => (
<div>{hello}</div>
);
// good
function Listing({ hello }) {
return <div>{hello}</div>
}
```
# 3. 命名
* 扩展名: 使用 .jsx 作为 React 组件的扩展名
* 文件名: 使用帕斯卡命名法命名文件,譬如 ReservationCard.jsx
* 引用命名: 使用帕斯卡命名法命名组件和 camelCase 命名实例
```js
// bad
const reservationCard = require('./ReservationCard')
// good
const ReservationCard = require('./ReservationCard')
```
* 模块命名: 模块使用当前文件名一样的名称. 比如 ReservationCard.jsx 应该包含名为 ReservationCard 的模块. 但是,如果整个文件夹是一个模块,使用 index.js 作为入口文件,然后直接使用 index.js 或者文件夹名作为模块的名称
```js
// bad
import Footer from './Footer/Footer';
// bad
import Footer from './Footer/index';
// good
import Footer from './Footer';
```
* 高阶模块命名: 对于生成一个新的模块,其中的模块名 displayName 应该为高阶模块名和传入模块名的组合. 例如, 高阶模块 withFoo(), 当传入一个 Bar 模块的时候, 生成的模块名 displayName 应该为 withFoo(Bar)
> 为什么?一个模块的 displayName 可能会在开发者工具或者错误信息中使用到,因此有一个能清楚的表达这层关系的值能帮助我们更好的理解模块发生了什么,更好地 Debug
```js
// 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;
}
```
# 4. 常见模式
## 1.多行书写
- 需要嵌套元素的任何情况下都应该多行书写
```html
// bad
<div><Header /><div><Main content={...} /></div></div>
// good
<div>
<Header />
<div>
<Main content={...} />
</div>
</div>
```
- 如果出现子节点不是元素,而是文本或变量这样的例外情况,那么应该和父节点的标签写在同一行,并避免产生混淆
```html
// good
<div>
<Alert>{message}</Alert>
<Button>Close</Button>
</div>
```
- 多行书写时,一定要记得用括号封装它们。JSX 本质上会替换成函数,由于自动分号插入机制的存在,另起一行的函数可能会导致意外结果。例如,在渲染方法内返回 JSX 代码,这也是 React 创建 UI 的方式
以下示例可以正常运行,因为 div 元素和返回在同一行
```js
return <div> /
```
但以下代码会失效
```js
return
<div />
```
因为它会转换为以下代码
```js
return;
React.createElement("div", null)
```
因此你需要将代码语句包裹在括号内:
```js
return (
<div />
)
```
## 2.多个属性的书写
如果元素有多个属性,一行书写一个属性,同时缩进一个层级,并保持结尾括号和开始标签对齐
```html
<button
foo="bar"
veryLongPropertyName="baz"
onSomething={this.handleSomething}
/>
```
## 3.条件语句
使用三元条件运算代替`if else`语句,代码更简洁
```html
<div>
{isLoggedIn ? <LogoutButton /> : <LoginButton />}
</div>
```
## 4.循环
如果在 JSX 模板中编写一个函数并返回数组,那么数组的每一项都会编译为一个元素
```html
<ul>
{users.map(user => <li>{user.name}</li>)}
</ul>
```
## 5.次级渲染
查看以下示例:
```js
renderUserMenu() {
// JSX 用于用户菜单
}
renderAdminMenu() {
// JSX 用于管理员菜单
}
render() {
return (
<div>
<h1>Welcome back!</h1>
{this.userExists && this.renderUserMenu() }
{this.userIsAdmin && this.renderAdminMenu() }
</div>
)
}
```
这种方法并不总是可以当作最佳实践,显然拆分组件的做法更好,有时这样做只是为了保持渲染方法的简洁。
# 5. 单引号与双引号
对于JSX 属性值总是使用双引号("), 其他均使用单引号(')
```html
// bad
<Foo bar='bar' />
// good
<Foo bar="bar" />
// bad
<Foo style={{ left: "20px" }} />
// good
<Foo style={{ left: '20px' }} />
```
# 6. 空格
JSX 处理文本和元素间的空格的方式与 HTML 不同,如以下代码片段
```html
<div>
<span>foo</span>
bar
<span>baz</span>
</div>
```
浏览器解析 HTML 时,以上代码会显示 foo bar baz
而 JSX 会将同一份代码渲染为 foobarbaz,这是因为嵌套的三行代码转译成了 div 元素的独立子元素,没有将空格计算在内。为了得到与 HTML 一致的输出结果,普通的解决方案是在元素间显式插入空格
```html
<div>
<span>foo</span>
{' '}
bar
{' '}
<span>baz</span>
</div>
```
这里用 JavaScriot 表达式封装了空字符串来强制编译器在元素间插入空格
另外注意以下两个书写规范
* 总是在自动关闭的标签前加一个空格,正常情况下也不需要换行
* 不要在JSX {} 引用括号里两边加空格
```html
// bad
<Foo bar={ baz } />
// good
<Foo bar={baz} />
```
# 7. 属性
JSX 不是一门标准语言,需要转译成 JavaScript,因此有些属性无法使用。
如我们需要用`className`取代`class`,用`htmlfor`取代`for`
```jsx
<label className="awesome-label" htmlFor="name" />
```
这是因为 class 和 for 都是 JavaScript 的保留字
# 8. 函数/方法
* 当在 render() 里使用事件处理方法时,提前在构造函数里把 this 绑定上去
> 为什么? 在每次 render 过程中, 再调用 bind 都会新建一个新的函数,浪费资源.
```jsx
// bad
class App extends React.Component {
onClickDiv() {
// do stuff
}
render() {
return <div onClick={this.onClickDiv.bind(this)} />;
}
}
// good
class App extends React.Component {
constructor(props) {
super(props);
this.onClickDiv = this.onClickDiv.bind(this);
}
onClickDiv() {
// do stuff
}
render() {
return <div onClick={this.onClickDiv} />;
}
}
```
# 9. 根元素
因为 JSX 元素会转换为 JavaScript 函数,但 JavaScript 不允许返回两个函数,因此如果有多个同级元素,需要强制将它们封装在一个父元素中
```html
<div />
<div />
error: Adjacent JSX elements must be wrapped in an enclosing tag
```
以下写法是有效的
```html
<div>
<div />
<div />
</div>
```
当然这么做有一个明显的缺点就是最外层多了一个不必要的DOM元素,`React.Fragment`组件能够在不额外创建 DOM 元素的情况下,让`render()`方法中返回多个元素。
```jsx
render() {
return (
<React.Fragment>
Some text.
<h2>A heading</h2>
</React.Fragment>
);
}
```
你也可以使用其简写语法`<></>`
```jsx
render() {
return (
<>
Some text.
<h2>A heading</h2>
More text.
<h2>Another heading</h2>
Even more text.
</>
);
}
```
# 10. 布尔属性值
如果设置某个属性却没有赋值,那么 JSX 会默认其值为 true,这种行为类似 HTML 的 disabled 属性
# 11. 展开属性
向子元素传递数据时,不要按引用方式传递整个 JavaScript 对象,而要使用对象的基本类型值以方便校验。这种做法很常见,并且引发的 bug 更少。
该特性的用法如下
```js
const foo = { id: 'bar' }
return <div {...foo} />
```
以上代码的转译结果如下
```js
var foo = { id: 'bar' };
return React.createElement('div', foo);
```
- 序言 & 更新日志
- H5
- Canvas
- 序言
- Part1-直线、矩形、多边形
- Part2-曲线图形
- Part3-线条操作
- Part4-文本操作
- Part5-图像操作
- Part6-变形操作
- Part7-像素操作
- Part8-渐变与阴影
- Part9-路径与状态
- Part10-物理动画
- Part11-边界检测
- Part12-碰撞检测
- Part13-用户交互
- Part14-高级动画
- CSS
- SCSS
- codePen
- 速查表
- 面试题
- 《CSS Secrets》
- SVG
- 移动端适配
- 滤镜(filter)的使用
- JS
- 基础概念
- 作用域、作用域链、闭包
- this
- 原型与继承
- 数组、字符串、Map、Set方法整理
- 垃圾回收机制
- DOM
- BOM
- 事件循环
- 严格模式
- 正则表达式
- ES6部分
- 设计模式
- AJAX
- 模块化
- 读冴羽博客笔记
- 第一部分总结-深入JS系列
- 第二部分总结-专题系列
- 第三部分总结-ES6系列
- 网络请求中的数据类型
- 事件
- 表单
- 函数式编程
- Tips
- JS-Coding
- Framework
- Vue
- 书写规范
- 基础
- vue-router & vuex
- 深入浅出 Vue
- 响应式原理及其他
- new Vue 发生了什么
- 组件化
- 编译流程
- Vue Router
- Vuex
- 前端路由的简单实现
- React
- 基础
- 书写规范
- Redux & react-router
- immutable.js
- CSS 管理
- React 16新特性-Fiber 与 Hook
- 《深入浅出React和Redux》笔记
- 前半部分
- 后半部分
- react-transition-group
- Vue 与 React 的对比
- 工程化与架构
- Hybird
- React Native
- 新手上路
- 内置组件
- 常用插件
- 问题记录
- Echarts
- 基础
- Electron
- 序言
- 配置 Electron 开发环境 & 基础概念
- React + TypeScript 仿 Antd
- TypeScript 基础
- 样式设计
- 组件测试
- 图标解决方案
- Algorithm
- 排序算法及常见问题
- 剑指 offer
- 动态规划
- DataStruct
- 概述
- 树
- 链表
- Network
- Performance
- Webpack
- PWA
- Browser
- Safety
- 微信小程序
- mpvue 课程实战记录
- 服务器
- 操作系统基础知识
- Linux
- Nginx
- redis
- node.js
- 基础及原生模块
- express框架
- node.js操作数据库
- 《深入浅出 node.js》笔记
- 前半部分
- 后半部分
- 数据库
- SQL
- 面试题收集
- 智力题
- 面试题精选1
- 面试题精选2
- 问答篇
- Other
- markdown 书写
- Git
- LaTex 常用命令