Airbnb React/JSX Style Guide重譯版


前言

本篇翻譯是重新翻譯Airbnb React/JSX Style Guide的內容。原先已有另一篇中文翻譯

這篇翻譯遵循了在這個翻譯指引 Translation Guide中的翻譯規則,希望能提供更容易閱讀與理解的翻譯內容。

Airbnb React/JSX Style Guide

對於 React 與 JSX 大部份情況下都適當的作法

Table of Contents

  1. 基本規則
  2. Class vs React.createClass vs stateless
  3. 命名
  4. 宣告
  5. 對齊
  6. 引號
  7. 空白
  8. 屬性(Props)
  9. 括號
  10. 標籤
  11. 方法
  12. 順序
  13. isMounted

基本規則

  • 在每個程式碼檔案中只包含一個React元件(component)
  • 必定使用 JSX 語法。
  • 不要使用React.createElement,除非你需要從一個不是JSX的檔案,來初始化應用程式。

Class(類別) vs React.createClass vs stateless(無狀態)

譯者註:ES6 Class的對於Mixins解決方式,可參考Mixins Are Dead. Long Live Composition

    // 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,建議連類別都不要使用,使用一般的函式就好(不要用箭頭函式(arrow functions)):


    // 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副檔名。
  • 檔案名稱: 檔案名稱使用巴斯卡(PascalCase)命名法。例如ReservationCard.jsx
  • 引用(Reference)命名: React元件使用巴斯卡(PascalCase)命名法,它們的實例則使用小駝峰(camelCase)命名法。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。不過,如果這是在一個目錄中的根(root)元件,則使用index.jsx作為檔案名稱,然後使用目錄名稱作為元件名稱:

    // bad
    import Footer from './Footer/Footer';
    
    // bad
    import Footer from './Footer/index';
    
    // good
    import Footer from './Footer';

宣告(Declaration)

  • 不要使用displayName來命名元件。而是用引用(reference)來命名元件。

    // 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屬性也使用這個慣例。

    // 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 />

Props(屬性)

  • 必定使用小駝峰(camelCase)命名法,來命名prop(屬性)名稱。

    // bad
    <Foo
      UserName="hello"
      phone_number={12345678}
    />
    
    // good
    <Foo
      userName="hello"
      phoneNumber={12345678}
    />
  • 當prop(屬性)是明確的true值時,省略它的數值。eslint: react/jsx-boolean-value

    // bad
    <Foo
      hidden={true}
    />
    
    // good
    <Foo
      hidden
    />

括號

  • 當JSX的程式碼超過一行時,用括號括住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, when single line
    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)

  • 在建構式(constructor)中綁定(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裡依照以下的順序:

    1. 可選擇的 static 方法
    2. constructor
    3. getChildContext
    4. componentWillMount
    5. componentDidMount
    6. componentWillReceiveProps
    7. shouldComponentUpdate
    8. componentWillUpdate
    9. componentDidUpdate
    10. componentWillUnmount
    11. clickHandlers 或 eventHandlers 例如 onClickSubmit()onChangeDescription()
    12. render用的getter方法 例如 getSelectReason()getFooterContent()
    13. 選擇性的render方法 例如renderNavigation()renderProfilePicture()
    14. 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裡依照以下的順序: eslint: react/sort-comp

    1. displayName
    2. propTypes
    3. contextTypes
    4. childContextTypes
    5. mixins
    6. statics
    7. defaultProps
    8. getDefaultProps
    9. getInitialState
    10. getChildContext
    11. componentWillMount
    12. componentDidMount
    13. componentWillReceiveProps
    14. shouldComponentUpdate
    15. componentWillUpdate
    16. componentDidUpdate
    17. componentWillUnmount
    18. clickHandlers 或 eventHandlers 例如 onClickSubmit()onChangeDescription()
    19. render用的getter方法 例如 getSelectReason()getFooterContent()
    20. 選擇性的render方法 例如renderNavigation()renderProfilePicture()
    21. render

isMounted

⬆ back to top