可能是React和JSX最合理编码规范
如果组件里面用到state
状态 &/ refs
,推荐使用class extends React.Component
,除非有非得已的理由必须用到mixins时, 才选择用React.createClass
// 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>;
}
}
如何组件中没有state和refs,推荐使用常规函数(非箭头函数)
// bad
class Listing extends React.Component {
render() {
return <div>{this.props.hello}div>;
}
}
// bad (relying on function name inference is discouraged)
// 箭头函数自动绑定this函数本身, 这是有风险的, 所以不推荐用箭头函数写stateless组件
const Listing = ({ hello }) => (
<div>{hello}div>
);
// good
function Listing({ hello }) {
return <div>{hello}div>;
}
.jsx
PascalCase
命名规范,就是大写驼峰格式,如:ReservationCard.jsxPascalCase
命名规范,组件实例用小写驼峰格式// bad
import reservationCard from './ReservationCard';
// good
import ReservationCard from './ReservationCard';
// bad
const ReservationItem = ;
// good
const reservationItem = ;
ReservationCard.jsx
文件中组件名为ReservationCard
;然后一个文件目录下的root
根组件使用index.jsx
来命名,同时以文件目录来命名该根组件// 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
"fancy" />
// good
"fancy" />
// bad
export default React.createClass({
displayName: 'ReservationCard',
// stuff goes here
});
// good
export default class ReservationCard extends React.Component {
}
// bad
<Foo superLongParam="bar"
anotherSuperLongParam="baz" />
// good
<Foo
superLongParam="bar"
anotherSuperLongParam="baz"
/>
// if props fit in one line then keep it on the same line
<Foo bar="bar" />
// children get indented normally
<Foo
superLongParam="bar"
anotherSuperLongParam="baz"
>
<Quux />
Foo>
只有JSX属性用”“双引号,其他情况下用单引号
为什么?常规HTML属性也是使用的是”“
// bad
<Foo bar='bar' />
// good
<Foo bar="bar" />
// bad
<Foo style={{ left: "20px" }} />
// good
<Foo style={{ left: '20px' }} />
// bad
// very bad
// bad
// good
// bad
<Foo bar={ baz } />
// good
<Foo bar={baz} />
// bad
<Foo
UserName="hello"
phone_number={12345678}
/>
// good
<Foo
userName="hello"
phoneNumber={12345678}
/>
// bad
true}
/>
// good
img
标签一定要有alt
属性,或必须有role="presentation"
// bad
"hello.jpg" />
// good
"hello.jpg" alt="Me waving hello" />
// good
"hello.jpg" alt="" />
// good
"hello.jpg" role="presentation" />
为什么? html解析器已经把 img 标签标注为图片了, 所以没有必要再在 alt 里说明了.
// bad
"hello.jpg" alt="Picture of me waving hello" />
// good
"hello.jpg" alt="Me waving hello" />
// bad - not an ARIA role
<div role="datepicker" />
// bad - abstract ARIA role
<div role="range" />
// good
<div role="button" />
为什么? html解析器在键盘快捷键与键盘命令时造成的不统一性会导致阅读性更加复杂.
// bad
<div accessKey="h" />
// good
<div />
// bad
{todos.map((todo, index) =>
)}
// good
{todos.map(todo => (
))}
// 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,
};
// bad
ref="myRef"
/>
// good
ref={(ref) => { this.myRef = ref; }}
/>
当JSX标签超过一行时,要将其包裹在圆括号()中
// bad
render() {
return <MyComponent className="long body" foo="bar">
<MyChild />
MyComponent>;
}
// good
render() {
return (
<MyComponent className="long body" foo="bar">
<MyChild />
MyComponent>
);
}
// good, when single line
render() {
const body = <div>hellodiv>;
return <MyComponent>{body}MyComponent>;
}
// bad
<Foo className="stuff">Foo>
// good
<Foo className="stuff" />
// bad
"bar"
baz="baz" />
// good
"bar"
baz="baz"
/>
function ItemList(props) {
return (
{props.items.map((item, index) => (
- doSomethingWith(item.name, index)}
/>
))
}
ul>
);
}
为什么? 在每次 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} />
}
}
为什么?_ 下划线前缀在某些语言中通常被用来表示私有变量或者函数。但是不像其他的一些语言,在JS中没有原生支持所谓的私有变量,所有的变量函数都是共有的。尽管你的意图是使它私有化,在之前加上下划线并不会使这些变量私有化,并且所有的属性(包括有下划线前缀及没有前缀的)都应该被视为是共有的。了解更多详情请查看Issue #1024, 和 #490 。
// bad
React.createClass({
_onClickSubmit() {
// do stuff
},
// other stuff
});
// good
class extends React.Component {
onClickSubmit() {
// do stuff
}
// other stuff
}
// bad
render() {
(<div />);
}
// good
render() {
return (<div />);
}
class extends React.Component
的生命周期函数: static
静态方法constructor
getChildContext
componentWillMount
… 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.url} data-id={this.props.id}>{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
一些规则,在实战中根据提示扩充。