­

團隊 React 代碼規範制定

  • 2019 年 11 月 25 日
  • 筆記

前言

團隊中每個開發人員的水平不同,技術關注點不同,如果沒有一份代碼規範的參照和約束,那麼項目中的代碼將會風格迥異,難以維護,為保證代碼質量和風格統一,特此擬定一份《團隊React 代碼規範》,這樣整個團隊的開發人員可以參照這份代碼規範進行編碼,從而讓團隊的代碼風格統一,利於維護。如果你的團隊還沒有這麼一份 React 代碼規範,也許這正是你需要的;如果你的團隊已經有了 React 代碼規範,這份規範也許能起到錦上添花的效果。

注意: JS、SCSS、Vue 的代碼規範可以查看作者之前寫的另一篇文章《前端團隊代碼評審 CheckList 清單》。

辛苦整理良久,還望手動點贊鼓勵~

github 地址:點擊此處,如果喜歡或者有所啟發,請幫忙給個 star ~,對作者也是一種鼓勵。

1、基礎規則

  • 一個文件聲明一個組件: 儘管可以在一個文件中聲明多個 React 組件,但是最好不要這樣做;推薦一個文件聲明一個 React 組件,並只導出一個組件;
  • 使用 JSX 表達式: 不要使用 React.createElement 的寫法;
  • 函數組件和 class 類組件的使用場景: 如果定義的組件不需要 props 和 state ,建議將組件定義成函數組件,否則定義成 class 類組件。

2、組件聲明

(1)組件名稱和定義該組件的文件名稱建議要保持一致;

推薦:

import Footer from './Footer';  複製代碼

不推薦:

import Footer from './Footer/index';  複製代碼

(2)不要使用 displayName 屬性來定義組件的名稱,應該在 class 或者 function 關鍵字後面直接聲明組件的名稱。

推薦:

export default class MyComponent extends React.Component {  }  複製代碼

不推薦:

export default React.Component({    displayName: 'MyComponent',  });  複製代碼

3、React 中的命名

  • 組件名稱: 推薦使用大駝峰命名;
  • 屬性名稱: React DOM 使用小駝峰命令來定義屬性的名稱,而不使用 HTML 屬性名稱的命名約定;
  • style 樣式屬性: 採用小駝峰命名屬性的 JavaScript 對象;

推薦:

// 組件名稱  MyComponent  // 屬性名稱  onClick  // 樣式屬性  backgroundColor  複製代碼

4、JSX 寫法注意

4.1、標籤

(1)當標籤沒有子元素的時候,始終使用自閉合的標籤 。

推薦:

// Good  <Component />  複製代碼

不推薦:

<Component></Component>  複製代碼

(2)如果標籤有多行屬性,關閉標籤要另起一行 。

推薦:

<Component    bar="bar"    baz="baz"  />  複製代碼

不推薦:

<Component    bar="bar"    baz="baz" />  複製代碼

(3)在自閉標籤之前留一個空格。

推薦:

<Foo />  複製代碼

不推薦:

<Foo/>    <Foo                 />    <Foo   />  複製代碼

(4)當組件跨行時,要用括號包裹 JSX 標籤。

推薦:

  render() {      return (        <MyComponent className="long body" foo="bar">          <MyChild />        </MyComponent>      );    }  複製代碼

不推薦:

  render() {      return <MyComponent className="long body" foo="bar">               <MyChild />             </MyComponent>;    }  複製代碼

4.2、對齊

JSX 語法使用下列的對齊方式 :

// 推薦  <Foo    superLongParam="bar"    anotherSuperLongParam="baz"  />    // 如果組件的屬性可以放在一行(一個屬性時)就保持在當前一行中  <Foo bar="bar" />    // 多行屬性採用縮進  <Foo    superLongParam="bar"    anotherSuperLongParam="baz"  >    <Quux />  </Foo>    // 不推薦  <Foo superLongParam="bar"       anotherSuperLongParam="baz" />  複製代碼

4.3、引號

JSX 的屬性都採用雙引號,其他的 JS 都使用單引號 ,因為 JSX 屬性 不能包含轉義的引號, 所以當輸入 "don't" 這類的縮寫的時候用雙引號會更方便。

推薦:

<Foo bar="bar" />    <Foo style={{ left: '20px' }} />  複製代碼

不推薦:

<Foo bar='bar' />    <Foo style={{ left: "20px" }} />  複製代碼

5、樣式寫法

React 中樣式可以使用 style 行內樣式,也可以使用 className 屬性來引用外部 CSS 樣式表中定義的 CSS 類,我們推薦使用 className 來定義樣式。並且推薦使用 SCSS 來替換傳統的 CSS 寫法,具體 SCSS 提高效率的寫法可以參照先前總結的文章。

6、defaultProps 使用靜態屬性定義

defaultProps 推薦使用靜態屬性定義,不推薦在 class 外進行定義。

推薦:

class Example extends React.Component {    static defaultProps = {      name: 'stranger'    }      render() {     // ...    }  }  複製代碼

不推薦:

class Example extends React.Component {    render() {      // ...    }  }    Example.propTypes = {    name: PropTypes.string  };  複製代碼

7、key 屬性設置

key 幫助 React 識別哪些元素改變了,比如被添加或刪除。因此你應當給數組中的每一個元素賦予一個確定的標識。當元素沒有確定 id 的時候,萬不得已你可以使用元素索引 index 作為 key,但是要主要如果列表項目的順序可能會變化,如果使用索引來用作 key 值,因為這樣做會導致性能變差,還可能引起組件狀態的問題。

推薦:

{todos.map(todo => (    <Todo      {...todo}      key={todo.id}    />  ))}  複製代碼

不推薦:

{todos.map((todo, index) =>    <Todo      {...todo}      key={index}    />  )}  複製代碼

8、為組件綁定事件處理器

React 為組件綁定事件處理器提供 4 種方法,有 public class fields 語法、構造函數中進行綁定、在回調中使用箭頭函數、使用 Function.prototype.bind 進行綁定,我們推薦使用 public class fields 語法,在不滿足需求情況下使用箭頭函數的寫法(傳遞參數給事件處理器)。

推薦:

 handleClick = () => {      console.log('this is:', this);   }   <button onClick={this.handleClick}> Click me </button>  複製代碼

不推薦:

 constructor(props) {      super(props);      this.handleClick = this.handleClick.bind(this);   }   handleClick(){      console.log('this is:', this);   }   <button onClick={this.handleClick}> Click me </button>  複製代碼

9、State

9.1、不要直接修改 state

除了 state 初始化外,其它地方修改 state,需要使用 setState( ) 方法,否則如果直接賦值,則不會重新渲染組件。

推薦:

this.setState({comment: 'Hello'});  複製代碼

不推薦:

this.state.comment = 'hello';  複製代碼

9.2、State 的更新可能是異步的

出於性能考慮,React 可能會把多個 setState( ) 調用合併成一個調用;因為 this.props 和 this.state 可能會異步更新,所以這種場景下需要讓 setState() 接收一個函數而不是一個對象 。

推薦:

this.setState((state, props) => ({    counter: state.counter + props.increment  }));  複製代碼

不推薦:

this.setState({    counter: this.state.counter + this.props.increment,  });    複製代碼

10、組件的代碼順序

組件應該有嚴格的代碼順序,這樣有利於代碼維護,我們推薦每個組件中的代碼順序一致性。

class Example extends Component {      // 靜態屬性      static defaultProps = {}        // 構造函數      constructor(props) {          super(props);          this.state={}      }        // 聲明周期鉤子函數      // 按照它們執行的順序      // 1. componentWillMount      // 2. componentWillReceiveProps      // 3. shouldComponentUpdate      // 4. componentDidMount      // 5. componentDidUpdate      // 6. componentWillUnmount      componentDidMount() { ... }        // 事件函數/普通函數      handleClick = (e) => { ... }        // 最後,render 方法      render() { ... }  }  複製代碼

11、使用高階組件

使用高階組件解決橫切關注點問題,而不是使用 mixins ,mixins 導致的相關問題可以參照文檔;

12、避免不必要 render 的寫法

shouldComponentUpdate 鉤子函數和 React.PureComponent 類都是用來當 state 和 props 變化時,避免不必要的 render 的方法。shouldComponentUpdate 鉤子函數需要自己手動實現淺比較的邏輯,React.PureComponent 類則默認對 props 和 state 進行淺層比較,並減少了跳過必要更新的可能性。我們推薦使用 React.PureComponent 避免不要的 render。

13、狀態提升

如果多個組件需要反映相同的變化數據,建議將共享狀態提升到最近的共同父組件中去;從而依靠自上而下的數據流,而不是嘗試在不同組件間同步 state。

14、推薦使用 Context

如果某個屬性在組件樹的不同層級的組件之間需要用到,我們應該使用 Context 提供在組件之間共享此屬性的方式,而不不是顯式地通過組件樹的逐層傳遞 props。

15、Refs 寫法

Refs 提供了一種方式,允許我們訪問 DOM 節點或在 render 方法中創建的 React 元素 。我們推薦使用 createRef API 的方式 或者 回調函數的方式使用 Refs ,而不是使用 this.refs.textInput 這種過時的方式訪問 refs ,因為它存在一些 問題。

16、路由加載

建議使用路由懶加載當前用戶所需要的內容,這樣能夠顯着地提高你的應用性能。儘管並沒有減少應用整體的代碼體積,但你可以避免加載用戶永遠不需要的代碼,並在初始加載的時候減少所需加載的代碼量。

推薦:

const OtherComponent = React.lazy(() => import('./OtherComponent'));  複製代碼

不推薦:

import OtherComponent from './OtherComponent';  複製代碼

17、AJAX 發起請求的時機

推薦在 componentDidMount這個生命周期函數中發起 AJAX 請求。這樣做你可以拿到 AJAX 請求返回的數據並通過 setState 來更新組件。