一份彙整了在 React 及 JSX 中被普遍使用的風格指南。
- 一個檔案只包含一個 React 元件。
- 不過,一個檔案可以有多個 Stateless 或 Pure Components。eslint:
react/no-multi-comp
.
- 不過,一個檔案可以有多個 Stateless 或 Pure Components。eslint:
- 總是使用 JSX 語法。
- 請別使用
React.createElement
,除非你初始化 app 的檔案不是 JSX。
-
如果你有內部 state 及 / 或 refs,使用
class extends React.Component
勝於React.createClass
,除非你有一個非常好的理由才使用 mixins。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,使用一般函式(不是箭頭函式)勝於 classes:
// 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
。 -
檔案名稱:檔案名稱請使用帕斯卡命名法。例如:
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.jsx
作為檔案名稱,並使用目錄名作為元件的名稱:// bad import Footer from './Footer/Footer'; // bad import Footer from './Footer/index'; // good import Footer from './Footer';
-
不要使用
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" /> // 如果 props 適合放在同一行,就將它們放在同一行上 <Foo bar="bar" /> // 通常子元素必須進行縮排 <Foo superLongParam="bar" anotherSuperLongParam="baz" > <Quux /> </Foo>
- 總是在 JSX 的屬性使用雙引號(
"
),但是所有的 JS 請使用單引號。eslint:jsx-quotes
為什麼?JSX 屬性不能包含跳脫的引號,所以雙引號可以更容易輸入像
"don't"
的連接詞。 一般的 HTML 屬性通常也使用雙引號而不是單引號,所以 JSX 屬性借鏡了這個慣例。
```javascript
// 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 />
-
總是使用駝峰式大小寫命名 prop。
// bad <Foo UserName="hello" phone_number={12345678} /> // good <Foo userName="hello" phoneNumber={12345678} />
-
Omit the value of the prop when it is explicitly
true
. eslint:react/jsx-boolean-value
// bad <Foo hidden={true} /> // good <Foo hidden />
-
當 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>; }
-
沒有子標籤時總是使用自身結尾標籤。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" />
-
Bind event handlers for the render method in the constructor. eslint:
react/jsx-no-bind
Why? A bind call in the render path creates a brand new function on every single 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
的排序:
- optional
static
methods constructor
getChildContext
componentWillMount
componentDidMount
componentWillReceiveProps
shouldComponentUpdate
componentWillUpdate
componentDidUpdate
componentWillUnmount
- clickHandlers 或 eventHandlers 像是
onClickSubmit()
或onChangeDescription()
- getter methods for
render
像是getSelectReason()
或getFooterContent()
- Optional render methods 像是
renderNavigation()
或renderProfilePicture()
render
-
How to define
propTypes
,defaultProps
,contextTypes
, etc...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
的排序:eslint:react/sort-comp
displayName
propTypes
contextTypes
childContextTypes
mixins
statics
defaultProps
getDefaultProps
getInitialState
getChildContext
componentWillMount
componentDidMount
componentWillReceiveProps
shouldComponentUpdate
componentWillUpdate
componentDidUpdate
componentWillUnmount
- clickHandlers 或 eventHandlers 像是
onClickSubmit()
或onChangeDescription()
- getter methods for
render
像是getSelectReason()
或getFooterContent()
- Optional render methods 像是
renderNavigation()
或renderProfilePicture()
render
- 切勿使用
isMounted
。eslint:react/no-is-mounted
為什麼?
isMounted
是個 anti-pattern,在 ES6 classes 不可使用,並且被正式棄用。