1. 程式人生 > >編碼規範-----react

編碼規範-----react

基本規範
  • 原則上每個檔案只寫一個元件, 多個無狀態元件可以放在單個檔案中. eslint: react/no-multi-comp.
  • 推薦使用 JSX 語法編寫 React 元件, 而不是 React.createElement
建立元件的三種方式

Class vs React.createClass vs stateless

  • // badconstListing=React.createClass({// ...
      render(){return<div>{this.state.hello}</div>;}});// goodclassListingextendsReact.Component
    {// ... render(){return<div>{this.state.hello}</div>;}}

    如果你的元件沒有狀態或是沒有引用refs, 推薦使用普通函式(非箭頭函式)而不是類:

    // badclassListingextendsReact.Component{
      render(){return<div>{this.props.hello}</div>;}}// bad (relying on function name inference is discouraged)constListing=({ hello })=>(<div>
    {hello}</div>);// goodfunctionListing({ hello }){return<div>{hello}</div>;}
Mixins
  • 因為 Mixins 會增加隱式依賴, 導致命名衝突, 並且會增加複雜度.大多數情況下, 可以更好的方法代替 Mixins, 如:元件化, 高階元件, 工具元件等.

命名
  • 副檔名: React 元件使用 .jsx 副檔名.
     - 檔名: 檔名使用帕斯卡命名. 如, ReservationCard.jsx.
     - 引用命名: React元件名使用帕斯卡命名, 例項使用駱駝式命名. eslint: react/jsx-pascal-case

    // badimport reservationCard from'./ReservationCard';// goodimportReservationCardfrom'./ReservationCard';// badconstReservationItem=<ReservationCard/>;// goodconst reservationItem =<ReservationCard/>;
  • 元件命名: 元件名與當前檔名一致. 如 ReservationCard.jsx 應該包含名為 ReservationCard的元件. 如果整個目錄是一個元件, 使用 index.js作為入口檔案, 然後直接使用 index.js 或者目錄名作為元件的名稱:

    // badimportFooterfrom'./Footer/Footer';// badimportFooterfrom'./Footer/index';// goodimportFooterfrom'./Footer';
  • 高階元件命名: 生成一個新的元件時, 其中的元件名 displayName 應該為高階元件名和傳入元件名的組合. 例如, 高階元件 withFoo(), 當傳入一個 Bar 元件的時候, 生成的元件名 displayName 應該為 withFoo(Bar).

    因為一個元件的 displayName 可能在除錯工具或錯誤資訊中使用到. 清晰合理的命名, 能幫助我們更好的理解元件執行過程, 更好的 Debug.

    // badexportdefaultfunction withFoo(WrappedComponent){returnfunctionWithFoo(props){return<WrappedComponent{...props} foo />;}}// goodexportdefaultfunction withFoo(WrappedComponent){functionWithFoo(props){return<WrappedComponent{...props} foo />;}const wrappedComponentName =WrappedComponent.displayName
        ||WrappedComponent.name
        ||'Component';WithFoo.displayName =`withFoo(${wrappedComponentName})`;returnWithFoo;}
  • 屬性命名: 避免使用 DOM 相關的屬性來用命名自定義屬性

    因為對於style 和 className 這樣的屬性名, 我們都會預設它們代表一些特殊的含義.

    // bad<MyComponent style="fancy"/>// good<MyComponent variant="fancy"/>
宣告元件
  • 不要使用 displayName 來命名 React 元件, 而是使用引用來命名元件, 如 class 名稱.

    // badexportdefaultReact.createClass({
      displayName:'ReservationCard',// stuff goes here});// goodexportdefaultclassReservationCardextendsReact.Component{}
程式碼縮排
  • // bad<Foo superLongParam="bar"
         anotherSuperLongParam="baz"/>// good, 有多行屬性的話, 新建一行關閉標籤<Foo
      superLongParam="bar"
      anotherSuperLongParam="baz"/>// 若能在一行中顯示, 直接寫成一行<Foo bar="bar"/>// 子元素按照常規方式縮排<Foo
      superLongParam="bar"
      anotherSuperLongParam="baz"><Quux/></Foo>
使用雙引號
  • 對於 JSX 屬性值總是使用雙引號("), 其他均使用單引號('). eslint: jsx-quotes

    因為 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/>
  • // bad<Foo bar={ baz }/>// good<Foo bar={baz}/>
屬性
  • JSX 屬性名使用駱駝式風格camelCase.

    // bad<FooUserName="hello"
      phone_number={12345678}/>// good<Foo
      userName="hello"
      phoneNumber={12345678}/>
  • // bad<Foo hidden={true}/>// good<Foo hidden />
  • <img> 標籤總是新增 alt 屬性. 如果圖片以陳述方式顯示, alt 可為空, 或者<img> 要包含role="presentation". eslint: jsx-a11y/alt-text

    // 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"/>
  • // bad - not an ARIA role<div role="datepicker"/>// bad - abstract ARIA role<div role="range"/>// good<div role="button"/>
  • 因為螢幕助讀器在鍵盤快捷鍵與鍵盤命令時造成的不統一性會導致閱讀性更加複雜.

    // bad<div accessKey="h"/>// good<div />
  • // bad{todos.map((todo, index)=><Todo{...todo}
      key={index}/>)}// good{todos.map(todo =>(<Todo{...todo}
      key={todo.id}/>))}
  • 對於所有非必填寫屬性, 總是手動去定義defaultProps屬性.

    因為 propTypes 可以作為元件的文件說明, 而宣告 defaultProps 使閱讀程式碼的人不需要去假設預設值. 另外, 顯式的宣告預設屬性可以讓你的元件跳過屬性型別的檢查.

    // badfunction SFC({ foo, bar, children }){return<div>{foo}{bar}{children}</div>;}
    
    SFC.propTypes ={
      foo:PropTypes.number.isRequired,
      bar:PropTypes.string,
      children:PropTypes.node,};// goodfunction SFC({ foo, bar, children }){return<div>{foo}{bar}{children}</div>;}
    SFC.propTypes ={
      foo:PropTypes.number.isRequired,
      bar:PropTypes.string,
      children:PropTypes.node,};
    SFC.defaultProps ={
      bar:'',
      children:null,};
Refs
  • // bad<Fooref="myRef"/>// good<Fooref={(ref)=>{this.myRef =ref;}}/>
括號
  • // 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>;}
標籤
  • // bad<Foo className="stuff"></Foo>// good<Foo className="stuff"/>
  • // bad<Foo
      bar="bar"
      baz="baz"/>// good<Foo
      bar="bar"
      baz="baz"/>
函式/方法
  • 使用箭頭函式來獲取本地變數.

    functionItemList(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 都會新建一個新的函式, 浪費資源.

    // badclassextendsReact.Component{
      onClickDiv(){// do stuff}
    
      render(){return<div onClick={this.onClickDiv.bind(this)}/>;}}// goodclassextendsReact.Component{
      constructor(props){super(props);this.onClickDiv =this.onClickDiv.bind(this);}
    
      onClickDiv(){// do stuff