# Airbnb React/JSX 风格指南 此风格指南主要基于目前流行的 JavaScript 标准。对于项目中是否应允许使用一些惯例(如 async/await,静态 class 属性等)的问题,应视具体情况而定。目前,本指南不包含并且不推荐使用任何第三阶段*前的功能。 > 译者注:第三阶段指 [TC39 流程](https://tc39.es/process-document/)中的 Stage 3 - Candidate。每个新的 ECMAScript 提案从起草到完成共分五个阶段。 ## 内容目录 1. [基本规范](#basic-rules-基本规范) 1. [Class、React.createClass 与 stateless](#创建模块) 1. [Mixins(混入)](#mixins) 1. [命名](#naming-命名) 1. [声明模块](#declaration-声明模块) 1. [代码对齐](#alignment-代码对齐) 1. [单引号还是双引号](#quotes-单引号还是双引号) 1. [空格](#spacing-空格) 1. [属性](#props-属性) 1. [Refs 引用](#refs) 1. [括号](#parentheses-括号) 1. [标签](#tags-标签) 1. [函数/方法](#methods-函数) 1. [模块生命周期](#ordering-react-模块生命周期) 1. [isMounted](#ismounted) ## Basic Rules 基本规范 - 每个文件只写一个模块. - 但多个[无状态模块](https://facebook.github.io/react/docs/reusable-components.html#stateless-functions)可以放在单个文件中. eslint: [`react/no-multi-comp`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-multi-comp.md#ignorestateless). - 推荐使用 JSX 语法. - 不要使用 `React.createElement`,除非在从一个非 JSX 的文件中初始化 app. - 只有在使用 `arrayOf`, `objectOf`, 或 `shape` 明确指出 `arrays` 和 `objects` 所包含的内容时,[`react/forbid-prop-types`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/forbid-prop-types.md) 才会允许这个属性 (props). ## 创建模块 Class vs React.createClass vs stateless - 如果你的模块有内部状态或者是`refs`, 推荐使用 `class extends React.Component` 而不是 `React.createClass`. eslint: [`react/prefer-es6-class`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/prefer-es6-class.md) [`react/prefer-stateless-function`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/prefer-stateless-function.md) ```jsx // bad const Listing = React.createClass({ // ... render() { return
{this.state.hello}
; } }); // good class Listing extends React.Component { // ... render() { return
{this.state.hello}
; } } ``` 如果你的模块没有状态或是没有引用`refs`, 推荐使用普通函数(非箭头函数)而不是类: ```jsx // bad class Listing extends React.Component { render() { return
{this.props.hello}
; } } // bad (relying on function name inference is discouraged) const Listing = ({ hello }) => (
{hello}
); // good function Listing({ hello }) { return
{hello}
; } ``` ## Mixins - [不要使用 mixins](https://facebook.github.io/react/blog/2016/07/13/mixins-considered-harmful.html). > 为什么? Mixins 会增加隐式的依赖,导致命名冲突,并且会以雪球式增加复杂度。在大多数情况下Mixins可以被更好的方法替代,如:组件化,高阶组件,工具模块等。 ## Naming 命名 - **扩展名**: React模块使用 `.jsx` 扩展名. >eslint: [`react/jsx-filename-extension`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-filename-extension.md) - **文件名**: 文件名使用帕斯卡命名. 如, `ReservationCard.jsx`. - **引用命名**: React模块名使用帕斯卡命名,实例使用骆驼式命名. eslint: [`react/jsx-pascal-case`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-pascal-case.md) ```jsx // bad import reservationCard from './ReservationCard'; // good import ReservationCard from './ReservationCard'; // bad const ReservationItem = ; // good const reservationItem = ; ``` - **模块命名**: 模块使用当前文件名一样的名称. 比如 `ReservationCard.jsx` 应该包含名为 `ReservationCard`的模块. 但是,如果整个文件夹是一个模块,使用 `index.js`作为入口文件,然后直接使用 `index.js` 或者文件夹名作为模块的名称: ```jsx // 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。 ```jsx // bad export default function withFoo(WrappedComponent) { return function WithFoo(props) { return ; } } // good export default function withFoo(WrappedComponent) { function WithFoo(props) { return ; } const wrappedComponentName = WrappedComponent.displayName || WrappedComponent.name || 'Component'; WithFoo.displayName = `withFoo(${wrappedComponentName})`; return WithFoo; } ``` - **属性命名**: 避免使用DOM相关的属性来用作其他的用途。 > 为什么?对于`style` 和 `className`这样的属性名,我们都会默认它们代表一些特殊的含义,如元素的样式,CSS class的名称。在你的应用中使用这些属性来表示其他的含义会使你的代码更难阅读,更难维护,并且可能会引起bug。 ```jsx // bad // good ``` ## Declaration 声明模块 - 不要使用 `displayName` 来命名React模块,而是使用引用来命名模块, 如 class 名称. ```jsx // bad export default React.createClass({ displayName: 'ReservationCard', // stuff goes here }); // good export default class ReservationCard extends React.Component { } ``` ## Alignment 代码对齐 - 遵循以下的JSX语法缩进/格式. eslint: [`react/jsx-closing-bracket-location`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-closing-bracket-location.md) [`react/jsx-closing-tag-location`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-closing-tag-location.md) ```jsx // bad // good // if props fit in one line then keep it on the same line // children get indented normally // bad {showButton &&