前言
一般在團隊開發中每個人的代碼習慣都不太一樣,這樣就會導致代碼風格不一致,以致於維護和修改bug的時候看別人的代碼成為一種痛苦...
這種情況尤其在前端開發中尤為明顯。因為關於前端的開發規范貌似也沒有行業權威標准。這幾天在網上看了下,基本上在開發中通過eslint進行約束,airbnb的標准貌似頗為推崇,今天稍微整理下,准備在日后開發中形成習慣。
基本規則
- 每個文件只包含一個React組件。eslint: react/no-multi-comp;(官方表示在無狀態,或者Pure組件允許一個文件包含多個組件,但是我個人覺得一個文件只包含一個組件比較淺顯易懂)
- 始終使用JSX語法;
- 不要始終React.createElement方法,除非初始化app的文件不是JSX格式;
Class vs React.createClass vs stateless
- 如果組件擁有內部的state或者refs時,更推薦使用class extends Component,除非有更好的理由使用mixin。eslint:react/prefer-es6-class
// 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 (因為箭頭函數沒有“name”屬性)
const Listing = ({ hello }) => (
<div>{hello}</div>
);
// good
function Listing({ hello }) {
return <div>{hello}</div>;
}
命名
- 拓展名:React組件使用.jsx擴展名;
- 文件名:文件名使用帕斯卡命名:HomePage.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 />;
聲明
不要使用displayName
屬性來命名組件,應該使用類的引用名稱。
// bad
export default React.createClass({
displayName: 'ReservationCard',
// stuff goes here
});
// good
export default class ReservationCard extends React.Component {
}
對齊
為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>
引號
JSX的屬性都采用雙引號,其他的JS都使用單引號:jsx-quotes。
為什么這樣做?JSX 屬性 不能包含轉義的引號, 所以當輸入"don't"這類的縮寫的時候用雙引號會更方便。
// bad
<Foo bar='bar' />
// good
<Foo bar="bar" />
// bad
<Foo style={{ left: "20px" }} />
// good
<Foo style={{ left: '20px' }} />
空格
始終在自閉和標簽前添加一個空格。
// bad
<Foo/>
// very bad
<Foo />
// bad
<Foo
/>
// good
<Foo />
屬性
- 屬性名稱始終使用駝峰命名法。
// 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
/>
括號
使用括號包裹多行JSX標簽,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, when single line
render() {
const body = <div>hello</div>;
return <MyComponent>{body}</MyComponent>;
}
標簽
- 當標簽沒有子元素的時候,始終使用自閉合的標簽: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"
/>
方法
在 render 方法中事件的回調函數,應該在構造函數中進行bind綁定。 eslint: react/jsx-no-bind。
為什么這樣做? 在 render 方法中的 bind 調用每次調用 render 的時候都會創建一個全新的函數。
// 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 組件的內部方法命名不要使用下划線前綴。
// bad
React.createClass({
_onClickSubmit() {
// do stuff
},
// other stuff
});
// good
class extends React.Component {
onClickSubmit() {
// do stuff
}
// other stuff
}
排序
class extends React.Component的順序:
- static靜態方法
- constructor
- getChildContext
- componentWillMount
- componentDidMount
- componentWillReceiveProps
- shouldComponentUpdate
- componentWillUpdate
- componentDidUpdate
- componentWillUnmount
- 點擊回調或者事件回調 比如 onClickSubmit() 或者 onChangeDescription()
- render函數中的 getter 方法 比如 getSelectReason() 或者 getFooterContent()
可選的 render 方法 比如 renderNavigation() 或者 renderProfilePicture()
- 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} 關於這個開發規范差不多就這樣吧,eslint的配置個人在研究下,下次再放出來</p>
來源:https://segmentfault.com/a/1190000017263310