Airbnb React/JSX 編碼規範

來自於Airbnb React/JSX 中文編碼規範javascript

Airbnb React/JSX 編碼規範

算是最合理的React/JSX編碼規範之一了html

Basic Rules 基本規範

  • 每一個文件只寫一個模塊.java

  • 推薦使用JSX語法.
  • 不要使用 React.createElement,除非從一個非JSX的文件中初始化你的app.

建立模塊

Class vs React.createClass vs statelessnode

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

// 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 或者文件夾名做爲模塊的名稱:git

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

// 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相關的屬性來用做其餘的用途。

爲何?對於styleclassName這樣的屬性名,咱們都會默認它們表明一些特殊的含義,如元素的樣式,CSS class的名稱。在你的應用中使用這些屬性來表示其餘的含義會使你的代碼更難閱讀,更難維護,而且可能會引發bug。github

// 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 的生命週期函數:
  1. 可選的 static 方法
  2. constructor 構造函數
  3. getChildContext 獲取子元素內容
  4. componentWillMount 模塊渲染前
  5. componentDidMount 模塊渲染後
  6. componentWillReceiveProps 模塊將接受新的數據
  7. shouldComponentUpdate 判斷模塊需不須要從新渲染
  8. componentWillUpdate 上面的方法返回 true, 模塊將從新渲染
  9. componentDidUpdate 模塊渲染結束
  10. componentWillUnmount 模塊將從DOM中清除, 作一些清理任務
  11. 點擊回調或者事件處理器onClickSubmit()onChangeDescription()
  12. render 裏的 getter 方法getSelectReason()getFooterContent()
  13. 可選的 render 方法renderNavigation()renderProfilePicture()
  14. 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
  1. displayName 設定模塊名稱
  2. propTypes 設置屬性的類型
  3. contextTypes 設置上下文類型
  4. childContextTypes 設置子元素上下文類型
  5. mixins 添加一些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 or eventHandlers like onClickSubmit() or onChangeDescription()
  19. getter methods for render like getSelectReason() or getFooterContent()
  20. Optional render methods like renderNavigation() or renderProfilePicture()
  21. render

isMounted

爲何? isMounted 反人類設計模式:(), 在 ES6 classes 中沒法使用, 官方將在將來的版本里刪除此方法.

相關文章
相關標籤/搜索