Airbnb React/JSX 编码范例
算是最合理的React/JSX编码范例之一了
Basic Rules 基础范例
每一个文件只写一个模块.
- 然则多个无状况模块能够放在单个文件中. eslint:
react/no-multi-comp
.
- 然则多个无状况模块能够放在单个文件中. eslint:
- 引荐运用JSX语法.
- 不要运用
React.createElement
,除非从一个非JSX的文件中初始化你的app.
建立模块
Class vs React.createClass vs stateless
- 假如你的模块有内部状况或许是
refs
, 引荐运用class extends React.Component
而不是React.createClass
,除非你有足够的来由来运用这些要领.
eslint:react/prefer-es6-class
react/prefer-stateless-function
// 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>;
}
}
假如你的模块没有状况或是没有援用`refs`, 引荐运用一般函数(非箭头函数)而不是类:
// bad
class Listing extends React.Component {
render() {
return <div>{this.props.hello}</div>;
}
}
// bad (relying on function name inference is discouraged)
const Listing = ({ hello }) => (
<div>{hello}</div>
);
// good
function Listing({ hello }) {
return <div>{hello}</div>;
}
Naming 定名
- 扩展名: React模块运用
.jsx
扩展名.
– 文件名: 文件名运用帕斯卡定名. 如,ReservationCard.jsx
.
– 援用定名: React模块名运用帕斯卡定名,实例运用骆驼式定名. eslint: react/jsx-pascal-case
// bad
import reservationCard from './ReservationCard';
// good
import ReservationCard from './ReservationCard';
// bad
const ReservationItem = <ReservationCard />;
// good
const reservationItem = <ReservationCard />;
模块定名: 模块运用当前文件名一样的称号. 比方
ReservationCard.jsx
应当包含名为ReservationCard
的模块. 然则,假如全部文件夹是一个模块,运用index.js
作为进口文件,然后直接运用index.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.
// 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;
}
- 属性定名: 防止运用DOM相干的属性来用作其他的用处。
为何?关于
style
和className
如许的属性名,我们都邑默许它们代表一些特别的寄义,如元素的款式,CSS class的称号。在你的运用中运用这些属性来示意其他的寄义会使你的代码更难浏览,更难保护,而且能够会引起bug。
// bad
<MyComponent style="fancy" />
// good
<MyComponent variant="fancy" />
Declaration 声明模块
不要运用
displayName
来定名React模块,而是运用援用来定名模块, 如 class 称号.// 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
// bad <Foo superLongParam="bar" anotherSuperLongParam="baz" /> // good, 有多行属性的话, 新建一行封闭标签 <Foo superLongParam="bar" anotherSuperLongParam="baz" /> // 若能在一行中显现, 直接写成一行 <Foo bar="bar" /> // 子元素根据通例体式格局缩进 <Foo superLongParam="bar" anotherSuperLongParam="baz" > <Quux /> </Foo>
Quotes 单引号照样双引号
- 关于JSX属性值老是运用双引号(
"
), 其他均运用单引号('
). eslint:jsx-quotes
为何? HTML属性也是用双引号, 因而JSX的属性也遵照此商定.
// bad
<Foo bar='bar' />
// good
<Foo bar="bar" />
// bad
<Foo style={{ left: "20px" }} />
// good
<Foo style={{ left: '20px' }} />
Spacing 空格
老是在自动封闭的标签前加一个空格,一般情况下也不需要换行. eslint:
no-multi-spaces
,react/jsx-space-before-closing
// bad <Foo/> // very bad <Foo /> // bad <Foo /> // good <Foo />
不要在JSX
{}
援用括号里双方加空格. eslint:react/jsx-curly-spacing
// bad <Foo bar={ baz } /> // good <Foo bar={baz} />
Props 属性
JSX属性名运用骆驼式作风
camelCase
.// bad <Foo UserName="hello" phone_number={12345678} /> // good <Foo userName="hello" phoneNumber={12345678} />
假如属性值为
true
, 能够直接省略. eslint:react/jsx-boolean-value
// bad <Foo hidden={true} /> // good <Foo hidden />
<img>
标签老是增加alt
属性. 假如图片以presentation(觉得是以相似PPT体式格局显现?)体式格局显现,alt
可为空, 或许<img>
要包含role="presentation"
. eslint:jsx-a11y/img-has-alt
// bad <img src="hello.jpg" /> // good <img src="hello.jpg" alt="Me waving hello" /> // good <img src="hello.jpg" alt="" /> // good <img src="hello.jpg" role="presentation" />
- 不要在
alt
值里运用如 “image”, “photo”, or “picture”包含图片寄义如许的词, 中文也一样. eslint:jsx-a11y/img-redundant-alt
为何? 屏幕助读器已把
img
标签标注为图片了, 所以没有必要再在alt
里说清楚明了.
// bad
<img src="hello.jpg" alt="Picture of me waving hello" />
// good
<img src="hello.jpg" alt="Me waving hello" />
运用有用准确的 aria
role
属性值 ARIA roles. eslint:jsx-a11y/aria-role
// bad - not an ARIA role <div role="datepicker" /> // bad - abstract ARIA role <div role="range" /> // good <div role="button" />
- 不要在标签上运用
accessKey
属性. eslint:jsx-a11y/no-access-key
为何? 屏幕助读器在键盘快捷键与键盘敕令时形成的不统一性会致使浏览性越发庞杂.
// bad
<div accessKey="h" />
// good
<div />
防止运用数组的index来作为属性
key
的值,引荐运用唯一ID. (为何?)// bad {todos.map((todo, index) => <Todo {...todo} key={index} /> )} // good {todos.map(todo => ( <Todo {...todo} key={todo.id} /> ))}
- 关于一切非必需的属性,老是手动去定义
defaultProps
属性.
为何? propTypes 能够作为模块的文档申明, 而且声明 defaultProps 的话意味着浏览代码的人不需要去假定一些默许值。更主要的是, 显现的声明默许属性能够让你的模块跳过属性范例的搜检.
// bad
function SFC({ foo, bar, children }) {
return <div>{foo}{bar}{children}</div>;
}
SFC.propTypes = {
foo: PropTypes.number.isRequired,
bar: PropTypes.string,
children: PropTypes.node,
};
// good
function SFC({ foo, bar }) {
return <div>{foo}{bar}</div>;
}
SFC.propTypes = {
foo: PropTypes.number.isRequired,
bar: PropTypes.string,
};
SFC.defaultProps = {
bar: '',
children: null,
};
Refs
老是在Refs里运用回调函数. eslint:
react/no-string-refs
// bad <Foo ref="myRef" /> // good <Foo ref={(ref) => { this.myRef = ref; }} />
Parentheses 括号
将多行的JSX标签写在
()
里. eslint:react/wrap-multilines
// bad render() { return <MyComponent className="long body" foo="bar"> <MyChild /> </MyComponent>; } // good render() { return ( <MyComponent className="long body" foo="bar"> <MyChild /> </MyComponent> ); } // good, 单行能够不需要 render() { const body = <div>hello</div>; return <MyComponent>{body}</MyComponent>; }
Tags 标签
关于没有子元素的标签来讲老是本身封闭标签. eslint:
react/self-closing-comp
// bad <Foo className="stuff"></Foo> // good <Foo className="stuff" />
假如模块有多行的属性, 封闭标签时新建一行. eslint:
react/jsx-closing-bracket-location
// bad <Foo bar="bar" baz="baz" /> // good <Foo bar="bar" baz="baz" />
Methods 函数
运用箭头函数来猎取当地变量.
function ItemList(props) { return ( <ul> {props.items.map((item, index) => ( <Item key={item.key} onClick={() => doSomethingWith(item.name, index)} /> ))} </ul> ); }
- 当在
render()
里运用事宜处置惩罚要领时,提早在组织函数里把this
绑定上去. eslint:react/jsx-no-bind
为何? 在每次
render
过程当中, 再挪用bind
都邑新建一个新的函数,浪费资源.
// bad
class extends React.Component {
onClickDiv() {
// do stuff
}
render() {
return <div onClick={this.onClickDiv.bind(this)} />
}
}
// good
class extends React.Component {
constructor(props) {
super(props);
this.onClickDiv = this.onClickDiv.bind(this);
}
onClickDiv() {
// do stuff
}
render() {
return <div onClick={this.onClickDiv} />
}
}
- 在React模块中,不要给所谓的私有函数增加
_
前缀,本质上它并非私有的.
为何?
_
下划线前缀在某些言语中通常被用来示意私有变量或许函数。然则不像其他的一些言语,在JS中没有原生支撑所谓的私有变量,一切的变量函数都是共有的。只管你的企图是使它私有化,在之前加上下划线并不会使这些变量私有化,而且一切的属性(包含有下划线前缀及没有前缀的)都应当被视为是共有的。相识更多详情请检察Issue #1024, 和 #490 。
// bad
React.createClass({
_onClickSubmit() {
// do stuff
},
// other stuff
});
// good
class extends React.Component {
onClickSubmit() {
// do stuff
}
// other stuff
}
在
render
要领中老是确保return
返回值. eslint:react/require-render-return
// bad render() { (<div />); } // good render() { return (<div />); }
Ordering React 模块性命周期
-
class extends React.Component
的性命周期函数:
- 可选的
static
要领 -
constructor
组织函数 -
getChildContext
猎取子元素内容 -
componentWillMount
模块衬着前 -
componentDidMount
模块衬着后 -
componentWillReceiveProps
模块将接收新的数据 -
shouldComponentUpdate
推断模块需不需要从新衬着 -
componentWillUpdate
上面的要领返回true
, 模块将从新衬着 -
componentDidUpdate
模块衬着完毕 -
componentWillUnmount
模块将从DOM中消灭, 做一些清算使命 - 点击回调或许事宜处置惩罚器 如
onClickSubmit()
或onChangeDescription()
-
render
里的 getter 要领 如getSelectReason()
或getFooterContent()
- 可选的 render 要领 如
renderNavigation()
或renderProfilePicture()
-
render
render() 要领
怎样定义
propTypes
,defaultProps
,contextTypes
, 等等其他属性…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 <a href={this.props.url} data-id={this.props.id}>{this.props.text}</a> } } Link.propTypes = propTypes; Link.defaultProps = defaultProps; export default Link;
-
React.createClass
的性命周期函数,与运用class稍有差别: eslint:react/sort-comp
-
displayName
设定模块称号 -
propTypes
设置属性的范例 -
contextTypes
设置上下文范例 -
childContextTypes
设置子元素上下文范例 -
mixins
增加一些mixins statics
-
defaultProps
设置默许的属性值 -
getDefaultProps
猎取默许属性值 -
getInitialState
或许初始状况 getChildContext
componentWillMount
componentDidMount
componentWillReceiveProps
shouldComponentUpdate
componentWillUpdate
componentDidUpdate
componentWillUnmount
- clickHandlers or eventHandlers like
onClickSubmit()
oronChangeDescription()
- getter methods for
render
likegetSelectReason()
orgetFooterContent()
- Optional render methods like
renderNavigation()
orrenderProfilePicture()
render
isMounted
- 不要再运用
isMounted
. eslint:react/no-is-mounted
为何?
isMounted
反人类设想形式:(), 在 ES6 classes 中没法运用, 官方将在将来的版本里删除此要领.