參考資料:https://github.com/sunyardTime/React-Native-CodeStyle 感謝情書哥無私奉獻 ##一、編程規約 ###(一) 命名規約 【強制】 代碼中命名均不能以下劃線或美元符號開始,也不能以下劃線或美元符號結束; 【強制】 代碼中命名嚴禁使用拼音與英文 ...
參考資料:https://github.com/sunyardTime/React-Native-CodeStyle
感謝情書哥無私奉獻
##一、編程規約 ###(一) 命名規約
【強制】 代碼中命名均不能以下劃線或美元符號開始,也不能以下劃線或美元符號結束;
`_name / $Object / name_ / name$ / Object$`
【強制】 代碼中命名嚴禁使用拼音與英文混合的方式,更不允許直接使用中文的方式; 說明:正確的英文拼寫和語法可以讓閱讀者易於理解,避免歧義。註意,即使純拼音命名方式 也要避免採用;
`反例: DaZhePromotion [打折] / getPingfenByName() [評分] / int 某變數 = 3`
【強制】類名使用 UpperCamelCase 風格,必須遵從駝峰形式,第一個字母必須大寫;
LoginPage/MsgPage
【強制】方法名、參數名、成員變數、局部變數都統一使用 lowerCamelCase風格,必須遵從駝峰形式,第一個字母必須小寫;
localValue / getHttpMessage() / inputUserId
【強制】常量命名全部大寫,單詞間用下劃線隔開,力求語義表達完整清楚,不要嫌名字長;
正例: MAX_STOCK_COUNT 反例: MAX_COUNT
【強制】使用抽象單詞命名類名或者變數時,需加以修飾;
userMsg 等價於 userMessaage, userPic 等價於 userPicture
【強制】中括弧是數組類型的一部分,數組定義如下:String[] args; 反例:請勿使用String args[]的方式來定義。
【強制】包名統一使用小寫,點分隔符之間有且僅有一個自然語義的英語單詞。包名統一使用單數形式,但是類名如果有複數含義,類名可以使用複數形式;
正例: 應用工具類包名為com.fcs.open.util、類名為UrlUtils
【強制】文件夾命名統一小寫; 組件,或者類名,首字母全部大寫,遵守駝峰命名法;
img 存放圖片 app APP一些component artcomponent 一些art組件
###(二) 常量定義
- 【強制】不允許出現任何魔法值(即未經定義的常量)直接出現在代碼中;
- 【推薦】不要使用一個常量類維護所有常量,應該按常量功能進行歸類,分開維護。 如:緩存相關的常量放在類:CacheConsts下; 系統配置相關的常量放在類:ConfigConsts下; 說明:大而全的常量類,非得使用查找功能才能定位到修改的常量,不利於理解和維護;
###(三) 格式規約
- 【強制】大括弧的使用約定。如果是大括弧內為空,則簡潔地寫成{}即可,不需要換行;如果 是非空代碼塊則:
- 左大括弧前不換行;
- 左大括弧後換行;
- 右大括弧前換行;
- 右大括弧後還有else等代碼則不換行‘;’表示終止右大括弧後必須換行。
- 【強制】 左括弧和後一個字元之間不出現空格;同樣,右括弧和前一個字元之間也不出現空格;
- 【強制】if/for/while/switch/do 等保留字與左右括弧之間都必須加空格;
- 【強制】任何運算符左右必須加一個空格; 說明:運算符包括賦值運算符=、邏輯運算符&&、加減乘除符號、三目運行符等;
- 【強制】縮進採用 4 個空格,禁止使用 tab 字元;
- 【強制】單行字元數限制不超過120個,超出需要換行,換行時遵循如下原則:
第二行相對第一行縮進4個空格,從第三行開始,不再繼續縮進,參考示例;
運算符與下文一起換行;
方法調用的點符號與下文一起換行;
在多個參數超長,逗號後進行換行;
const path = Path() .moveTo(0, -radius/2) .arc(0, radius, 1) .arc(0, -radius, 1) .close();
【強制】方法參數在定義和傳入時,多個參數逗號後邊必須加空格;
onMsgByCallAndMsg=(msg, title, type)=>{ this.setState({ callMsgAndMsg:msg }) }
【推薦】方法體內的執行語句組、變數的定義語句組、不同的業務邏輯之間或者不同的語義之間插入一個空行。相同業務邏輯和語義之間不需要插入空行。 說明:沒有必要插入多行空格進行隔開。
【推薦】使用webStomr時,導入附件的hoop-settings-1.0.jar文件,可統一格式化。
###(四) package.json
【強制】在使用npm或者yarn獲取資源時,必須在命令末尾添加--save; 說明:使用此命令會把使用的第三方相關信息寫入到package.json,這樣,其他成員在下載或者更新代碼後使用npm i,就可以下載最新的npm,若不加 —save ,執行npm i的時候不會下載,其他成員運行項目後在運行可能會報錯,此時需要分析查看報錯信息進行重新的npm install XX;
【推薦】使用git或者svn進行代碼版本管理時,儘量不上傳node_module文件; 說明:使用package.json進行包管理,下載或更新代碼後,只需要執行npm i;當有修改npm包,建議進行版本管理,上傳到私有的github倉庫。
【強制】使用第三方或拉取新倉庫時,第一步使用npm i或者npm install; 說明:檢查版本是否存在衝突
【推薦】在使用npm或者yarn獲取資源時,推薦不在命令後添加 -g; 說明,此命令可以讓此資源包在根目錄進行獲取,不利於資源管理;
【強制】當升級或降級react-native版本時,必須進行代碼備份; 說明:升級失敗或者涉及到原生代碼時,可以進行代碼回滾
【強制】每個項目必須配置一個readMe文件,內容包括測試,正式環境等相關配置文件以及註意事項;
【推薦】安裝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可以得到修複。
###(五) 控制語句
【強制】在一個 switch 塊內,每個case要麼通過 break/return 等來終止,要麼註釋說明程式將繼續執行到哪一個 case 為止;在一個 switch 塊內,都必須包含一個default 語句並且 放在最後,即使它什麼代碼也沒有。
【強制】在 if/else/for/while/do 語句中必須使用大括弧,即使只有一行代碼,避免使用 下麵的形式:
if (condition) statements;
【推薦】推薦儘量少用 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) { ... }
###(六) 註釋規約
【強制】類、類屬性、類方法的註釋必須使用 Javadoc 規範,使用/*內容/格式,不得使用 //xxx 方式; 說明:在 IDE 編輯視窗中,Javadoc 方式會提示相關註釋,生成 Javadoc 可以正確輸出相應註釋;在 IDE 中,工程調用方法時,不進入方法即可懸浮提示方法、參數、返回值的意義,提高閱讀效率。
【強制】所有的類都必須添加創建者信息,以及類的說明;
【強制】方法內部單行註釋,在被註釋語句上方另起一行,使用//註釋; 方法內部多行註釋使用/* */註釋,註意與代碼對齊。
【強制】所有的常量類型欄位必須要有註釋,說明每個值的用途;
【參考】註釋掉的代碼儘量要配合說明,而不是簡單的註釋掉。 說明:代碼被註釋掉有兩種可能性: 1)後續會恢復此段代碼邏輯。 2)永久不用。前者如果沒有備註信息,難以知曉註釋動機。後者建議直接刪掉(代碼倉庫保存了歷史代碼)。
【參考】對於註釋的要求: 第一、能夠準確反應設計思想和代碼邏輯; 第二、能夠描述業務含義,使別的程式員能夠迅速瞭解到代碼背後的信息。完全沒有註釋的大段代碼對於閱讀者形同 天書,註釋是給自己看的,即使隔很長時間,也能清晰理解當時的思路;註釋也是給繼任者看的,使其能夠快速接替自己的工作。
【參考】好的命名、代碼結構是自解釋的,註釋力求精簡準確、表達到位。避免出現註釋的一個極端:過多過濫的註釋,代碼的邏輯一旦修改,修改註釋是相當大的負擔。
【參考】特殊註釋標記,請註明標記人與標記時間。註意及時處理這些標記,通過標記掃描,經常清理此類標記。
- 待辦事宜(TODO):( 標記人,標記時間,[預計處理時間]) 表示需要實現,但目前還未實現的功能。
- 錯誤,不能工作:(標記人,標記時間,[預計處理時間]) 在註釋中用 FIXME標記某代碼是錯誤的,而且不能工作,需要及時糾正的情況。
###(七) 日誌管理
【推薦】 代碼中過多使用console.log()會消耗性能,推薦去除不必要的日誌輸入代碼;
【強制】 在入口文件添加以下代碼; 說明:可以在發佈時屏蔽掉所有的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
【強制】 代碼中初始化state因在constructor(props)函數中,而且儘量對每個變數進行註釋;
【強制】 代碼中使用setState時,因註意非同步可能導致的問題,儘量使用回調函數;
this.setState({ //todo },()=>{ //執行setState後執行此函數 })
【強制】 代碼中使用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,[email protected],[email protected]圖片,併在代碼引用中,使用如下方式:
<Image style={{flex: 1, height: screenHeight, width: screenWidth}} source={require('../XX.png')}>
說明:當使用XX.png時,程式運行過程中會根據不同屏幕尺寸獲取不同資源;當使用如下方式:
<Image style={{flex: 1, height: screenHeight, width: screenWidth}} source={require('../[email protected]')}>
時,程式運行過程中不會根據不同屏幕尺寸獲取不同資源。 註意:此方式適用於React-Native0.46.0版本之前。
9.【強制】在React-Native版本大於0.46.0使用本地資源,圖片命名不能出現‘@’符號: 說明:不同大小圖片需要原生不同的尺寸文件夾,系統自動進行不同適配。
###(二) 樣式
【強制】 當組件使用樣式屬性達到三個或者三個以上時,必須使用StyleSheet來創建樣式屬性併進行引用;
const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#F5FCFF', marginTop:10, }, });
【推薦】 當使用單一屬性,或者全局樣式屬性時,推薦使用公共樣式類;
//StyleCommon.js module.exports={ topColor:{ backgroundColor: '#3A3D42', }, mainView:{ backgroundColor: '#12141B', }, }
【推薦】 當使用多個state或者props值時,推薦使用以下方式;
const {size, dotRadius, color} = this.props; const { maxNumber,minNumber,}=this.state;
說明使用此方式,代碼結構清晰簡潔,便於維護;
###(三) var,let,const
- 【強制】對所有變數,對象的引用,使用const,不要使用var;
- 【推薦】如果一定需要引用可變動的變數,對象,建議使用let代替var;
###(四) 代碼間隔
- 【強制】使用ES6編寫代碼,定義方法時,每個方法結尾使用‘;’進行分隔;
###(五) 其他
【強制】對組件引用,變數引用,需遵從以下方式;
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'
【推薦】對組件引用,變數初始化等,在整個頁面或組件內未使用,因去除相關代碼;
##三、編碼約定
###(一)入口文件
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.【推薦】根據附件,配置代碼編寫模版,推薦使用第二種配置方式,可配置多種模版。
##四、自定義組件 (一) 自定義組件
【強制】組件命名中必須包含Component; 說明:
ButtonComponent.js LabelComponent.js
【強制】組件中定義的state和props必須都要有註釋,依次說明每個值的含義;
【強制】在每個類的頭部註釋中,必須使用/**/說明此組件的基礎使用方式以及特殊使用方法;
(二) 屬性判斷
【強制】代碼中使用props時,需進行propTypes檢測和defaultProps預設值初始化;
static propTypes = { color: PropTypes.string, dotRadius: PropTypes.number, size: PropTypes.number };
static defaultProps = { color: '#1e90ff', dotRadius: 10, size: 40 };
(三) 性能優化
【強制】無狀態組件需使用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 }); }
##五、安全規約
【強制】用戶敏感數據禁止直接展示,必須對展示數據脫敏; 說明:查看個人手機號碼會顯示成:158****9119,隱藏中間 4 位,防止隱私泄露
【強制】請求傳入任何參數必須做有效性驗證;避免過度請求服務,造成伺服器壓力,或者雙向校驗; 如:驗證手機號長度,是否是手機號等;
##六、其他
【推薦】開發工具使用WebStorm,安裝ESLint插件進行代碼檢測,代碼中不要出現使用ESLint檢查出的錯誤; 說明:變數命名規範,使用var或者const錯誤
【推薦】在WebStorm中導入附件的hoop-settings.jar文件,進行代碼格式化,提交的任何代碼,都需要進行格式化。快捷鍵是option+command+L