React Native中的約束規範

weixin_34391854發表於2017-08-29


 

參考資料:https://github.com/sunyardTime/React-Native-CodeStyle

感謝情書哥無私奉獻

##一、程式設計規約 ###(一) 命名規約

  1. 【強制】 程式碼中命名均不能以下劃線或美元符號開始,也不能以下劃線或美元符號結束;

    `_name / $Object / name_ / name$ / Object$`
    
  2. 【強制】 程式碼中命名嚴禁使用拼音與英文混合的方式,更不允許直接使用中文的方式; 說明:正確的英文拼寫和語法可以讓閱讀者易於理解,避免歧義。注意,即使純拼音命名方式 也要避免採用;

    `反例: DaZhePromotion [打折] / getPingfenByName() [評分] / int 某變數 = 3`
    
  3. 【強制】類名使用 UpperCamelCase 風格,必須遵從駝峰形式,第一個字母必須大寫; LoginPage/MsgPage

  4. 【強制】方法名、引數名、成員變數、區域性變數都統一使用 lowerCamelCase風格,必須遵從駝峰形式,第一個字母必須小寫;

    localValue / getHttpMessage() / inputUserId

  5. 【強制】常量命名全部大寫,單詞間用下劃線隔開,力求語義表達完整清楚,不要嫌名字長; 正例: MAX_STOCK_COUNT 反例: MAX_COUNT

  6. 【強制】使用抽象單詞命名類名或者變數時,需加以修飾; userMsg 等價於 userMessaage, userPic 等價於 userPicture

  7. 【強制】中括號是陣列型別的一部分,陣列定義如下:String[] args; 反例:請勿使用String args[]的方式來定義。

  8. 【強制】包名統一使用小寫,點分隔符之間有且僅有一個自然語義的英語單詞。包名統一使用單數形式,但是類名如果有複數含義,類名可以使用複數形式; 正例: 應用工具類包名為com.fcs.open.util、類名為UrlUtils

  9. 【強制】資料夾命名統一小寫; 元件,或者類名,首字母全部大寫,遵守駝峰命名法;

     img    存放圖片
     app    APP一些component
     artcomponent    一些art元件
    


###(二) 常量定義

  1. 【強制】不允許出現任何魔法值(即未經定義的常量)直接出現在程式碼中;
  2. 【推薦】不要使用一個常量類維護所有常量,應該按常量功能進行歸類,分開維護。 如:快取相關的常量放在類:CacheConsts下; 系統配置相關的常量放在類:ConfigConsts下; 說明:大而全的常量類,非得使用查詢功能才能定位到修改的常量,不利於理解和維護;


###(三) 格式規約

  1. 【強制】大括號的使用約定。如果是大括號內為空,則簡潔地寫成{}即可,不需要換行;如果 是非空程式碼塊則:
  1. 左大括號前不換行;
  2. 左大括號後換行;
  3. 右大括號前換行;
  4. 右大括號後還有else等程式碼則不換行‘;’表示終止右大括號後必須換行。
  1. 【強制】 左括號和後一個字元之間不出現空格;同樣,右括號和前一個字元之間也不出現空格;
  2. 【強制】if/for/while/switch/do 等保留字與左右括號之間都必須加空格;
  3. 【強制】任何運算子左右必須加一個空格; 說明:運算子包括賦值運算子=、邏輯運算子&&、加減乘除符號、三目執行符等;
  4. 【強制】縮排採用 4 個空格,禁止使用 tab 字元;
  5. 【強制】單行字元數限制不超過120個,超出需要換行,換行時遵循如下原則:
  1. 第二行相對第一行縮排4個空格,從第三行開始,不再繼續縮排,參考示例;

  2. 運算子與下文一起換行;

  3. 方法呼叫的點符號與下文一起換行;

  4. 在多個引數超長,逗號後進行換行;

     const path = Path()
             .moveTo(0, -radius/2)
             .arc(0, radius, 1)
             .arc(0, -radius, 1)
             .close();
    
  1. 【強制】方法引數在定義和傳入時,多個引數逗號後邊必須加空格;

     onMsgByCallAndMsg=(msg, title, type)=>{
         this.setState({
             callMsgAndMsg:msg
         })
     }
    
  2. 【推薦】方法體內的執行語句組、變數的定義語句組、不同的業務邏輯之間或者不同的語義之間插入一個空行。相同業務邏輯和語義之間不需要插入空行。 說明:沒有必要插入多行空格進行隔開。

  3. 【推薦】使用webStomr時,匯入附件的hoop-settings-1.0.jar檔案,可統一格式化。


###(四) package.json

  1. 【強制】在使用npm或者yarn獲取資源時,必須在命令末尾新增--save; 說明:使用此命令會把使用的第三方相關資訊寫入到package.json,這樣,其他成員在下載或者更新程式碼後使用npm i,就可以下載最新的npm,若不加 —save ,執行npm i的時候不會下載,其他成員執行專案後在執行可能會報錯,此時需要分析檢視報錯資訊進行重新的npm install XX;

  2. 【推薦】使用git或者svn進行程式碼版本管理時,儘量不上傳node_module檔案; 說明:使用package.json進行包管理,下載或更新程式碼後,只需要執行npm i;當有修改npm包,建議進行版本管理,上傳到私有的github倉庫。

  3. 【強制】使用第三方或拉取新倉庫時,第一步使用npm i或者npm install; 說明:檢查版本是否存在衝突

  4. 【推薦】在使用npm或者yarn獲取資源時,推薦不在命令後新增 -g; 說明,此命令可以讓此資源包在根目錄進行獲取,不利於資源管理;

  5. 【強制】當升級或降級react-native版本時,必須進行程式碼備份; 說明:升級失敗或者涉及到原生程式碼時,可以進行程式碼回滾

  6. 【強制】每個專案必須配置一個readMe檔案,內容包括測試,正式環境等相關配置檔案以及注意事項;

  7. 【推薦】安裝npm包是,推薦~來標記版本號; 說明:~和^的作用和區別:會匹配最近的小版本依賴包,比如1.2.3會匹配所有1.2.x版本,但是不包括1.3.0 ^會匹配最新的大版本依賴包,比如^1.2.3會匹配所有1.x.x的包,包括1.3.0,但是不包括2.0.0。那麼該如何選擇呢?當然你可以指定特定的版本號,直接寫1.2.3,前面什麼字首都沒有,這樣固然沒問題,但是如果依賴包釋出新版本修復了一些小bug,那麼需要手動修改package.json檔案;和^則可以解決這個問題。但是需要注意^版本更新可能比較大,會造成專案程式碼錯誤,舊版本可能和新版本存在部分程式碼不相容。所以推薦使用來標記版本號,這樣可以保證專案不會出現大的問題,也能保證包中的小bug可以得到修復。


###(五) 控制語句

  1. 【強制】在一個 switch 塊內,每個case要麼通過 break/return 等來終止,要麼註釋說明程式將繼續執行到哪一個 case 為止;在一個 switch 塊內,都必須包含一個default 語句並且 放在最後,即使它什麼程式碼也沒有。

  2. 【強制】在 if/else/for/while/do 語句中必須使用大括號,即使只有一行程式碼,避免使用 下面的形式: if (condition) statements;

  3. 【推薦】推薦儘量少用 else, if-else 的方式可以改寫成:

     if(condition){
                   ...
     return obj; }
    

// 接著寫 else 的業務邏輯程式碼; 說明:如果非得使用

if()
...
else if(

)...else...

方式表達邏輯,【強制】請勿超過3層, 超過請使用狀態設計模式。 正例:邏輯上超過 3 層的 if-else 程式碼可以使用衛語句,或者狀態模式來實現。

4.【推薦】使用三目運算,替換if else結構,精簡程式碼

let   account=5;
if(account>10){
        console.log("true");
}else {
        console.log("false");
}

let msg=account>10?"true":"false";

5.【推薦】除常用方法(如 getXxx/isXxx)等外,不要在條件判斷中執行其它複雜的語句,將復 雜邏輯判斷的結果賦值給一個有意義的布林變數名,以提高可讀性。 說明:很多 if 語句內的邏輯相當複雜,閱讀者需要分析條件表示式的最終結果,才能明確什麼 樣的條件執行什麼樣的語句,那麼,如果閱讀者分析邏輯表示式錯誤呢?

        //虛擬碼如下
boolean existed = (file.open(fileName, "w") != null)&& (...) || (...); 
        if (existed) {
            ... 
         }

###(六) 註釋規約

  1. 【強制】類、類屬性、類方法的註釋必須使用 Javadoc 規範,使用/*內容/格式,不得使用 //xxx 方式; 說明:在 IDE 編輯視窗中,Javadoc 方式會提示相關注釋,生成 Javadoc 可以正確輸出相應註釋;在 IDE 中,工程呼叫方法時,不進入方法即可懸浮提示方法、引數、返回值的意義,提高閱讀效率。

  2. 【強制】所有的類都必須新增建立者資訊,以及類的說明;

  3. 【強制】方法內部單行註釋,在被註釋語句上方另起一行,使用//註釋; 方法內部多行註釋使用/* */註釋,注意與程式碼對齊。

  4. 【強制】所有的常量型別欄位必須要有註釋,說明每個值的用途;

  5. 【參考】註釋掉的程式碼儘量要配合說明,而不是簡單的註釋掉。 說明:程式碼被註釋掉有兩種可能性: 1)後續會恢復此段程式碼邏輯。 2)永久不用。前者如果沒有備註資訊,難以知曉註釋動機。後者建議直接刪掉(程式碼倉庫儲存了歷史程式碼)。

  6. 【參考】對於註釋的要求: 第一、能夠準確反應設計思想和程式碼邏輯; 第二、能夠描述業務含義,使別的程式設計師能夠迅速瞭解到程式碼背後的資訊。完全沒有註釋的大段程式碼對於閱讀者形同 天書,註釋是給自己看的,即使隔很長時間,也能清晰理解當時的思路;註釋也是給繼任者看的,使其能夠快速接替自己的工作。

  7. 【參考】好的命名、程式碼結構是自解釋的,註釋力求精簡準確、表達到位。避免出現註釋的一個極端:過多過濫的註釋,程式碼的邏輯一旦修改,修改註釋是相當大的負擔。

  8. 【參考】特殊註釋標記,請註明標記人與標記時間。注意及時處理這些標記,通過標記掃描,經常清理此類標記。

  1. 待辦事宜(TODO):( 標記人,標記時間,[預計處理時間]) 表示需要實現,但目前還未實現的功能。
  2. 錯誤,不能工作:(標記人,標記時間,[預計處理時間]) 在註釋中用 FIXME標記某程式碼是錯誤的,而且不能工作,需要及時糾正的情況。

###(七) 日誌管理

  1. 【推薦】 程式碼中過多使用console.log()會消耗效能,推薦去除不必要的日誌輸入程式碼;

  2. 【強制】 在入口檔案新增以下程式碼; 說明:可以在釋出時遮蔽掉所有的console.*呼叫。React Native中有一個全域性變數__DEV__用於指示當前執行環境是否是開發環境。我們可以據此在正式環境中替換掉系統原先的console實現。

     if (!__DEV__) {
       global.console = {
         info: () => {},
         log: () => {},
         warn: () => {},
         error: () => {},
       };
     }
    

這樣在打包釋出時,所有的控制檯語句就會被自動替換為空函式,而在除錯時它們仍然會被正常呼叫。

###(八) 目錄結構規範

    以下目錄結構示例中只展示js與靜態資源,不包含原生程式碼:
├── index.ios.js
├── index.android.js
└── js
    ├── component  			可複用的元件(非完整頁面)
    ├── page       			完整頁面
    ├── config 				配置項(常量、介面地址、路由、多語言化等預置資料)
    ├── util				工具類(非UI元件)
    ├── style				全域性樣式
    └── image				圖片
在component和page目錄中,可能還有一些內聚度較高的模組再建目錄

page/component
├── HomeView.component.js
├── HomeView.style.js
└── MovieView
    ├── MovieList.component.js  		
    ├── MovieList.style.js       	
    ├── MovieCell.component.js 			
    ├── MovieCell.style.js				
    ├── MovieView.component.js			
    └── MovieView.style.js				

##二、頁面編寫規範 ###(一) state,props

  1. 【強制】 程式碼中初始化state因在constructor(props)函式中,而且儘量對每個變數進行註釋;

  2. 【強制】 程式碼中使用setState時,因注意非同步可能導致的問題,儘量使用回撥函式;

     this.setState({
            //todo 
         },()=>{
            //執行setState後執行此函式
         })
    
  3. 【強制】 程式碼中使用props時,需進行propTypes檢測和defaultProps預設值初始化;

     static propTypes = {
             color: PropTypes.string,
             dotRadius: PropTypes.number,
             size: PropTypes.number
         };
     
     static defaultProps = {
             color: '#1e90ff',
             dotRadius: 10,
             size: 40
         };
    

4.【強制】 程式碼中用於頁面展示處理UI的元件,命名以Page結尾,自定義元件命名中必須包含Component; 例子:

 LoginPage           登入頁
 BtuuonComponent     按鈕元件

5.【強制】程式碼中建立陣列或物件使用以下方式;

const user={
        name:'time',
        sex:'男',
        age:25,
    };

const itemArray=['0','1','2',3,{name:'25',age:'男'}];

6.【強制】程式碼中函式繫結this,強制使用箭頭函式; 注:除元件原有方法,其他自定義函式命名時,需使用箭頭函式;

//系統元件生命週期方法
constructor(props){
    super(props);
};
//自定義方法
goMainPage=()=>{
    
};

7.【推薦】程式碼中一些網路資料初始化,配置資訊,推薦在此生命週期進行初始化;

componentWillMount

8.【強制】程式碼中使用定時器或者DeviceEventEmitter,必須在元件解除安裝進行銷燬或者清除;

componentDidMount() {
    //注意addListener的key和emit的key保持一致
    this.msgListener = DeviceEventEmitter.addListener('Msg',(listenerMsg) => {
        this.setState({
            listenerMsg:listenerMsg,
        })
    });
}

goMainPage=()=>{
    this.timer = setTimeout(
        () => { console.log('把一個定時器的引用掛在this上'); },
        500
    );
};


componentWillUnmount() {
    //此生命週期內,去掉監聽和定時器
    this.msgListener&&this.msgListener.remove();
    // 如果存在this.timer,則使用clearTimeout清空。
    // 如果你使用多個timer,那麼用多個變數,或者用個陣列來儲存引用,然後逐個clear
    this.timer && clearTimeout(this.timer);
}

9.【強制】使用本地圖片資源時,需設定寬高並進行適當適配;

 imgHeight=screenHeight, imgWidth= screenWidth

10.【強制】在React-Native版本小於0.46.0使用本地圖片資源時,當不指定特殊尺寸圖片時,需引入不同尺寸XX.png,XX2@.png,XX3@.png圖片,並在程式碼引用中,使用如下方式:

<Image style={{flex: 1, height: screenHeight, width: screenWidth}}
      source={require('../XX.png')}>

說明:當使用XX.png時,程式執行過程中會根據不同螢幕尺寸獲取不同資源;當使用如下方式:

<Image style={{flex: 1, height: screenHeight, width: screenWidth}}
           source={require('../XX2@.png')}>

時,程式執行過程中不會根據不同螢幕尺寸獲取不同資源。 注意:此方式適用於React-Native0.46.0版本之前。

9.【強制】在React-Native版本大於0.46.0使用本地資源,圖片命名不能出現‘@’符號: 說明:不同大小圖片需要原生不同的尺寸資料夾,系統自動進行不同適配。

###(二) 樣式

  1. 【強制】 當元件使用樣式屬性達到三個或者三個以上時,必須使用StyleSheet來建立樣式屬性並進行引用;

     const styles = StyleSheet.create({
         container: {
             flex: 1,
             justifyContent: 'center',
             alignItems: 'center',
             backgroundColor: '#F5FCFF',
             marginTop:10,
         },
     });
    
  2. 【推薦】 當使用單一屬性,或者全域性樣式屬性時,推薦使用公共樣式類;

     //StyleCommon.js
     module.exports={
         topColor:{
             backgroundColor: '#3A3D42',
         },
         mainView:{
             backgroundColor: '#12141B',
         },
     }
    
  3. 【推薦】 當使用多個state或者props值時,推薦使用以下方式;

      const {size, dotRadius, color} = this.props;
      const { maxNumber,minNumber,}=this.state;
    

說明使用此方式,程式碼結構清晰簡潔,便於維護;

###(三) var,let,const

  1. 【強制】對所有變數,物件的引用,使用const,不要使用var;
  2. 【推薦】如果一定需要引用可變動的變數,物件,建議使用let代替var;

###(四) 程式碼間隔

  1. 【強制】使用ES6編寫程式碼,定義方法時,每個方法結尾使用‘;’進行分隔;

###(五) 其他

  1. 【強制】對元件引用,變數引用,需遵從以下方式;

     import React, {Component} from 'react';
     import{
               View,
               Text,
               TouchableHighlight,
               Image,
               StyleSheet,
               InteractionManager,
     } from 'react-native';
     //from react,react-native優先;
     //from npm庫其次;
     import { connect } from 'react-redux';
              
     //from 專案內元件其次;
     import LoadingAndTime from '../component/LoadingAndTime';
     import { performLoginAction } from '../action/LoginAction'
     import {encode} from '../common/Base64';
     
     //變數初始化,常量初始化 最後;
     let screenWidth = Dimensions.get('window').width;
     let screenHeight = Dimensions.get('window').height;
     let typeCode = Platform.OS == 'android' ? 'android-phone' : 'ios-phone'
     let selectColor=Platform.OS=='android'?null:'white'
    
  2. 【推薦】對元件引用,變數初始化等,在整個頁面或元件內未使用,因去除相關程式碼;


##三、編碼約定

###(一)入口檔案

1.【推薦】統一入口檔案為App.js; 說明:在index.android.js和index.ios.js檔案中,統一入口檔案為App.js,且保持所在目錄和index.android.js和index.ios.js同級。

2.【強制】開發中,不要使用任何後端的開發模式來構建APP結構,如使用MVC,MVP,MVVM等開發模式,React-Native推薦元件化,顆粒化,以上設計模式嚴重違背。若使用Redux,Mobx等資料流第三方,可依據第三方結構編寫構建App。

###(二) 模版檔案

1.【推薦】根據附件,配置程式碼編寫模版,推薦使用第二種配置方式,可配置多種模版。


##四、自定義元件 (一) 自定義元件

  1. 【強制】元件命名中必須包含Component; 說明:

    ButtonComponent.js LabelComponent.js

  2. 【強制】元件中定義的state和props必須都要有註釋,依次說明每個值的含義;

  3. 【強制】在每個類的頭部註釋中,必須使用/**/說明此元件的基礎使用方式以及特殊使用方法;

(二) 屬性判斷

  1. 【強制】程式碼中使用props時,需進行propTypes檢測和defaultProps預設值初始化;

    static propTypes = { color: PropTypes.string, dotRadius: PropTypes.number, size: PropTypes.number };

    static defaultProps = { color: '#1e90ff', dotRadius: 10, size: 40 };

(三) 效能優化

  1. 【強制】無狀態元件需使用PureComponent而不是Component; 說明:無狀態元件是指內部沒有使用state的元件,但是可以使用props來進行某些屬性控制;

    export default class LinkButton extends PureComponent { static defaultProps= { msgName:'請輸入此事件函式名!' };

     static  propTypes={
         msgName:PropTypes.string.isRequired,
         onPressCall:PropTypes.func,
     };
    
    
     render() {
         return (
             <View style={styles.container}>
                 <TouchableOpacity onPress={this.onPressCall} >
                     <View>
                         <Text>{this.props.msgName}</Text>
                     </View>
                 </TouchableOpacity>
             </View>
         );
     }
    
     onPressCall=()=>{
         if(this.props.onPressCall){
             this.props.onPressCall();
         }
     }
    

    }

2.【推薦】使用InteractionManager.runAfterInteractions,在動畫或者某些特定場景中利用InteractionManager來選擇性的渲染新場景所需的最小限度的內容; 使用場景類似於:

    class ExpensiveScene extends React.Component {
      constructor(props, context) {
        super(props, context);
        this.state = {renderPlaceholderOnly: true};
      }
    
      componentDidMount() {
        InteractionManager.runAfterInteractions(() => {
          this.setState({renderPlaceholderOnly: false});
        });
      }
    
      render() {
        if (this.state.renderPlaceholderOnly) {
          return this._renderPlaceholderView();
        }
    
        return (
          <View>
            <Text>Your full view goes here</Text>
          </View>
        );
      }
    
    
      _renderPlaceholderView() {
        return (
          <View>
            <Text>Loading...</Text>
          </View>
        );
      }
    };

說明:更多使用於Navigator的頁面跳轉 3.【推薦】使用新版本元件替換舊辦法元件; 例如:FlatList替換ListView,React Navigation替換Navigator等

4.【推薦】在使用Touchable系列元件時,進行setState或者大量調幀操作,請使用如下方式:

handleOnPress() {
          this.requestAnimationFrame(() => {
             //todo
          });
     }




##五、安全規約

  1. 【強制】使用者敏感資料禁止直接展示,必須對展示資料脫敏; 說明:檢視個人手機號碼會顯示成:158****9119,隱藏中間 4 位,防止隱私洩露

  2. 【強制】請求傳入任何引數必須做有效性驗證;避免過度請求服務,造成伺服器壓力,或者雙向校驗; 如:驗證手機號長度,是否是手機號等;

##六、其他

  1. 【推薦】開發工具使用WebStorm,安裝ESLint外掛進行程式碼檢測,程式碼中不要出現使用ESLint檢查出的錯誤; 說明:變數命名規範,使用var或者const錯誤

  2. 【推薦】在WebStorm中匯入附件的hoop-settings.jar檔案,進行程式碼格式化,提交的任何程式碼,都需要進行格式化。快捷鍵是option+command+L

相關文章