Airbnb React/JSX Style Guide
可能是React和JSX最合理编码规范
基本规则(Basic Rules)
单个文件只包含一个React组件 单个文件可以有多个Stateless无状态组件组合,或多个纯组件 尽可能使用JSX语法 不要使用React.createElement,除非是从非jsx文件来初始化app创建组件
Class vs React.createClass vs stateless
如果组件里面用到state状态 &/ refs,推荐使用class extends React.Component,除非有非得已的理由必须用到mixins时, 才选择用React.createClass
// bad
const Listing = React.createClass({
// ...
render() {
return
{this.state.hello}
; } }); // good class Listing extends React.Component { // ... render() { return{this.state.hello}
; } }如何组件中没有state和refs,推荐使用常规函数(非箭头函数)
// bad
class Listing extends React.Component {
render() {
return
{this.props.hello}
; } } // bad (relying on function name inference is discouraged) // 箭头函数自动绑定this函数本身, 这是有风险的, 所以不推荐用箭头函数写stateless组件 const Listing = ({ hello }) => ({hello}
); // good function Listing({ hello }) { return{hello}
; }命名(Naming)
扩展名: React组件后缀使用.jsx 文件名:使用PascalCase命名规范,就是大写驼峰格式,如:ReservationCard.jsx 引用命名:组件使用PascalCase命名规范,组件实例用小写驼峰格式// bad import reservationCard from './ReservationCard'; // good import ReservationCard from './ReservationCard'; // bad const ReservationItem =组件命名:文件名和组件名一致,如:ReservationCard.jsx 文件中组件名为ReservationCard ;然后一个文件目录下的root 根组件使用index.jsx来命名,同时以文件目录来命名该根组件; // good const reservationItem = ;
// bad import Footer from './Footer/Footer'; // bad import Footer from './Footer/index'; // good import Footer from './Footer';
使用场景1:
. /Common/ ./Loading.jsx => export { Loading } ./Error.jsx => export { Error } ./index.jsx => export * from './Loading'; export * from './Error'; import { Loading, Error } from './Common'; import Common from './Common'; // 使用时用Common.Loading
高阶组件名:
理解高阶组件可参考
属性命名:避免使用DOM组件的原有属性名
// bad// good
声明组件(Declaration)
// bad
export default React.createClass({
displayName: 'ReservationCard',
// stuff goes here
});
// good
export default class ReservationCard extends React.Component {
}
代码对齐(Alignment)
// bad// good // if props fit in one line then keep it on the same line // children get indented normally
Quotes(引号)
只有JSX属性用”“双引号,其他情况下用单引号
为什么?常规HTML属性也是使用的是”“
// bad// good // bad // good
空格(Spacing)
自关闭标签前要空出一个空格// bad不要在JSX花括号 {} 两边加空格.// very bad // bad // good
// bad// good
属性(Props)
JSX属性名使用小写骆驼式// bad属性的值为true时可省略// good
// badimg标签一定要有alt属性,或必须有role="presentation"// good
// bad
// good
// good
// good
不要在 alt 值里使用如 “image”, “photo”, or “picture”包括图片含义这样的词
为什么? html解析器已经把 img 标签标注为图片了, 所以没有必要再在 alt 里说明了.
// bad
// good
使用有效正确的 aria role属性值 ARIA roles.
// bad - not an ARIA role
// bad - abstract ARIA role
// good
不要在标签上使用 accessKey 属性.
为什么? html解析器在键盘快捷键与键盘命令时造成的不统一性会导致阅读性更加复杂.
// bad
// good
避免使用数组的index来作为属性key的值,推荐使用唯一ID.(why?)
// bad
{todos.map((todo, index) =>
)}
// good
{todos.map(todo => (
))}
对于非required属性要有defaultProps默认属性值
// bad
function SFC({ foo, bar, children }) {
return
{foo}{bar}{children}
; } SFC.propTypes = { foo: PropTypes.number.isRequired, bar: PropTypes.string, children: PropTypes.node, }; // good function SFC({ foo, bar }) { return{foo}{bar}
; } SFC.propTypes = { foo: PropTypes.number.isRequired, bar: PropTypes.string, }; SFC.defaultProps = { bar: '', children: null, };引用(Refs)
// bad// good { this.myRef = ref; }} />
Parentheses
当JSX标签超过一行时,要将其包裹在圆括号()中
// bad
render() {
return
;
}
// good
render() {
return (
);
}
// good, when single line
render() {
const body =
hello
; return标签(Tags)
对于没有子元素的标签,使用自闭格式// bad如果模块有多行的属性, 新建一行关闭标签// good
// bad// good
方法(Methods)
使用箭头函数来掩盖当前变量
function ItemList(props) {
return (
- {props.items.map((item, index) => (
- doSomethingWith(item.name, index)} /> ))}
在constructor构造函数中绑定render方法中用到的事件处理函数
为什么? 在每次 render 过程中, 再调用 bind 都会新建一个新的函数,浪费资源.
// bad
class extends React.Component {
onClickDiv() {
// do stuff
}
render() {
return
} } // good class extends React.Component { constructor(props) { super(props); this.onClickDiv = this.onClickDiv.bind(this); } onClickDiv() { // do stuff } render() { return
} }
不要使用_前缀来命名内部方法
为什么?_ 下划线前缀在某些语言中通常被用来表示私有变量或者函数。但是不像其他的一些语言,在JS中没有原生支持所谓的私有变量,所有的变量函数都是共有的。尽管你的意图是使它私有化,在之前加上下划线并不会使这些变量私有化,并且所有的属性(包括有下划线前缀及没有前缀的)都应该被视为是共有的。了解更多详情请查看Issue #1024, 和 #490 。
// bad
React.createClass({
_onClickSubmit() {
// do stuff
},
// other stuff
});
// good
class extends React.Component {
onClickSubmit() {
// do stuff
}
// other stuff
}
确保 render 方法中总是return返回值
// bad
render() {
(
); } // good render() { return (
); }
组件的生命周期(Ordering)
class extends React.Component 的生命周期函数:1、可选的static 静态方法 2、constructor 3、getChildContext 4、componentWillMount …
【余下生命周期可参考】(https://github.com/mqy1023/react-with-es6/tree/master/06%E3%80%81lifecyclemethods)
import React, { PropTypes } from 'react';
const propTypes = {
id: PropTypes.number.isRequired,
url: PropTypes.string.isRequired,
text: PropTypes.string,
};
const defaultProps = {
text: 'Hello World',
};
class Link extends React.Component {
static methodsAreOk() {
return true;
}
render() {
return {this.props.text}
}
}
Link.propTypes = propTypes;
Link.defaultProps = defaultProps;
export default Link;
对于上面这么多最佳编码规范,在开发中当然不能完全自觉顾及到,需要加入静态检查代码,对于不好的编码实时提示,当然有很多种方式,如下只是一种参考:
1、npm install --save-dev eslint eslint-config-airbnb eslint-plugin-import eslint-plugin-jsx-a11y eslint-plugin-react
2、在工程目录下新建.eslintrc 配置规则
{
"extends": "airbnb",
"env": {
"node": true,
},
"ecmaFeatures": {
"forOf": true,
"jsx": true,
"es6": true
},
"rules": {
"comma-dangle": 0,
"react/prop-types": 0,
"react/forbid-prop-types": 0,
"max-len": ["warn", 120],
"no-floating-decimal": 0
}
}
上面省略了很多rules, 毕竟airbnb限制得太多太死,主要是用于取消airbnb 一些规则,在实战中根据提示扩充。