>[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 基礎
- React + ts
- 樣式設計
- 組件測試
- 圖標解決方案
- Storybook 的使用
- Input 組件
- 在線 mock server
- 打包與發布
- Algorithm
- 排序算法及常見問題
- 劍指 offer
- 動態規劃
- DataStruct
- 概述
- 樹
- 鏈表
- Network
- Performance
- Webpack
- PWA
- Browser
- Safety
- 微信小程序
- mpvue 課程實戰記錄
- 服務器
- 操作系統基礎知識
- Linux
- Nginx
- redis
- node.js
- 基礎及原生模塊
- express框架
- node.js操作數據庫
- 《深入淺出 node.js》筆記
- 前半部分
- 后半部分
- 數據庫
- SQL
- 面試題收集
- 智力題
- 面試題精選1
- 面試題精選2
- 問答篇
- 2025面試題收集
- Other
- markdown 書寫
- Git
- LaTex 常用命令
- Bugs