React Native 開發規范

一、關于命名

(1) 代碼中命名均不能以下劃線或美元符號開始,也不能以下劃線或美元符號結束

[反例]_name / $Object / name_ / name$ / Object$

(2)代碼中命名嚴禁使用拼音與英文混合的方式,更不允許直接使用中文的方式

[反例]DaZhePromotion [打折] / getPingfenByName() [評分] / int 某變量 = 3

(3)類名使用 UpperCamelCase 風格,必須遵從駝峰形式,第一個字母必須大寫

/**
 *作者:郭翰林
 * 時間:2018/8/3 0003 17:10
 * 注釋:安心管分享頁面
 */
export default class AnXinSharePage extends PureComponent {

(4)方法名、參數名、成員變量、局部變量都統一使用 lowerCamelCase風格,必須遵從駝峰形式,第一個字母必須小寫

  constructor(props) {
    super(props);
    this.isFromNative = this.props.navigation.state.params ? false : true;
    this.params = this.props.navigation.state.params || this.props.screenProps;
    this.state = {
      /**
       * 分數
       */
      score: 200,
      /**
       * 百分比
       */
      percent: "20%",
    };
  }
    
 /**
   * 作者:郭翰林
   * 時間:2018/7/26 0026 16:40
   * 注釋:綁定按鈕
   */
  componentDidMount() {
    this.props.navigation.setParams({onBack: this.onBack.bind(this)});
    this.props.navigation.setParams({onShare: this.onShare.bind(this)});
  }

(5)常量命名全部大寫,單詞間用下劃線隔開,力求語義表達完整清楚,不要嫌名字長,記得加注釋便于后人理解

export const FamilyMemberKey = {
  /**
   * 關系
   */
  RELATION: "relation",
  /**
   * 身份證號
   */
  IDCARD: "idCard",
  /**
   * 姓名
   */
  NAME: "name",
  /**
   * 性別
   */
  SEX: "gender",
  /**
   * 地址
   */
  ADDRESS: "address",
  /**
   * 生日
   */
  BIRTHDAY: "birthday",
  /**
   * 英文名
   */
  ENGNAME: "engName",
  /**
   * 手機號
   */
  MOBILE: "mobile",
  /**
   * 身高
   */
  HEIGHT: "height"
}

(6)圖片命名、文件夾命名統一小寫

image

二、關于代碼格式化

(1)IDE統一設置格式化規范,如下圖設置

image

(2)import 導入,一個import獨占一行

import {Image, ImageBackground, NativeModules, ScrollView, StyleSheet, Text, View} from 'react-native';
import React, {PureComponent} from 'react';
import {StyleConfig} from "../../resources/style";
import {SafeAreaView} from "react-navigation";
import Button from 'react-native-button';
import {XAnimatedProgress} from '@xyz/react-native-xprogress';

(3)外部樣式格式化,左括號必須強制換行,一個屬性獨占一行,以強制換行右括號結尾

const styles = StyleSheet.create({
  main: {
    flex: 1,
  },
  messageStyle: {
    marginTop: 65,
    marginHorizontal: 43.5,
  },
  progressViewStyle: {
    marginTop: 39,
    alignItems: "center"
  },
  shareViewStyle: {
    width: StyleConfig.screen_width,
    marginTop: 67,
    marginBottom: 37,
    justifyContent: "center",
    alignItems: "center"
  },
});

(4)少用行內樣式,如果是組件屬性則應換行展示

  /**
   * 作者:郭翰林
   * 時間:2018/8/3 0003 12:15
   * 注釋:繪制分數進度條
   */
  renderProgressView() {
    return (
      <View style={styles.progressViewStyle}>
        <XAnimatedProgress
          style={{}}
          fill={this.state.score}
          rate={1500}
          gradientStartColor="#ffffff"
          gradientEndColor="#ffffff"
          width={185}
          height={220}
          dashOffset={533}
          innerPath="M88,188 C88,188 13,163 13,75.5 C13,13 25.5,13 88,13 C150.5,13 163,13 163,75.5 C163,163 88,188 88,188 Z"
          progressWidth={15}
          shadowOffset={0}
          outerTransformOne="translate(-212.000000, -482.000000)"
          outerTransformTwo="translate(212.000000, 482.000000)"
          innerTransformOne="translate(-217.000000, -487.000000)"
          innerTransformTwo="translate(212.000000, 482.000000)"
          startTransparent={1}
          endTransparent={0.2}
          children={this.renderChildView}/>
      </View>
    );
  }

(5)提交代碼之前必須格式化代碼和刪除未使用的import

三、關于代碼注釋

(1)類、類方法的注釋必須使用 Javadoc 規范,使用//格式,不得使用 //xxx 方式*

  /**
   * 作者:郭翰林
   * 時間:2018/8/3 0003 11:51
   * 注釋:繪制頭部信息和進度條
   */
  renderHeaderView() {
    let message;
    if (this.state.score < 300) {
      message = "近乎裸奔行走江湖的勇士,抵抗風險全靠精神意念。";
    } else if (300 <= this.state.score && this.state.score < 550) {
      message = "沒心沒肺沒煩惱,膽大心不細,全憑運氣好。";
    } else if (550 <= this.state.score && this.state.score < 700) {
      message = "徘徊在及格線邊緣的糾結癥患者,完善保障要趁早哦。";
    } else if (700 <= this.state.score && this.state.score < 800) {
      message = "筑起保障再去勇闖四方,像你這樣靠譜的人已經不多啦。";
    } else {
      message = "你就是傳說中那個能讓家人安全感爆棚,兼具責任與使命感的家庭守護衛士。";
    }
    return (
      <View style={styles.messageStyle}>
        <Text style={{fontSize: 24, color: StyleConfig.color_white, textAlign: "center"}}>{message}</Text>
        {this.renderProgressView()}
      </View>
    );
  }

(2)所有的類都必須添加創建者信息,以及類的說明

/**
 * 作者:郭翰林
 * 時間:2018/7/26 0026 8:48
 * 注釋:更新家庭成員資料
 */
class UpdateFamilyMemberPage extends PureComponent {

(3)方法內部單行注釋,在被注釋語句上方另起一行,使用//注釋

/**
 * 作者:郭翰林
 * 時間:2018/7/27 0027 20:11
 * 注釋:獲取用戶信息
 * @returns {Promise<void>}
 */
async getUserInfo() {
    this.userInfo = await UserBridge.getUser();
    if (this.userInfo) {
        //獲取性別
        if (Platform.OS === "ios") {
            const {gender} = this.userInfo;
            this.setState({gender: gender});
        } else {
            const {linkman: {gender}} = this.userInfo;
            this.setState({gender: gender});
        }
        //是否實名認證
        const {authStatus} = this.userInfo;
        this.setState({authStatus: authStatus});
    }
}

(4)JSX復雜頁面繪制應該抽出單獨組件,復雜邏輯應添加注釋標記

<ScrollView style={{flex: 1, backgroundColor: StyleConfig.color_background}}
            contentContainerStyle={{paddingTop: 0, paddingBottom: 0}}
            automaticallyAdjustContentInsets={false}
            keyboardShouldPersistTaps="handled"
            showsHorizontalScrollIndicator={false}
            showsVerticalScrollIndicator={false}>
    <View>
        {/*個人資料*/}
        <PersonalDataView
                props={this.props} 
                isAdd={false}
                isShowRelationship={this.state.insurantId ? true : false}
                gender={this.state.gender}
                authStatus={this.state.authStatus ? this.state.authStatus : -1}
        />
        {/*生活習慣*/}
        <LifeHabitView props={this.props}/>
        {/*職業信息*/}
        <JobInfoView props={this.props}/>
        {/*財務信息*/}
        <FinanceInfoView props={this.props}/>
        <View style={{height: 44, alignItems: 'center', marginTop: 30}}>
            <XLargeButton onPress={() => this.filterUpdate()}>保存</XLargeButton>
        </View>
        <View style={{alignItems: 'center', marginTop: 30, marginBottom: 40}}>
            <Text style={styles.textStyle}>個人信息僅用于給你提供新一站服務時使用。</Text>
        </View>
    </View>
</ScrollView>
import {  View,StyleSheet,} from 'react-native';
import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
import ItemSectionView from "./ItemSectionView";
import Picker from '../../../components/views/picker/index';
import {XListItem} from '../../../components/antd/XList';
import {FamilyMemberKey,OftenDrinking,OftenDriving,OftenExercising,OftenSmoking} from "../constants/FamilyMemberConst";

/**
 * 作者:郭翰林
 * 時間:2018/7/26 0026 18:08
 * 注釋:生活習慣頁面
 */
export default class LifeHabitView extends PureComponent {
    static propTypes = {
        props: PropTypes.any,
    }

    constructor(props) {
        super(props);
        this.state = {};
    }

    render() {
        const {getFieldProps} = this.props.props.form;
        return (
            <View style={{flex:1}}>
                <ItemSectionView sectionName={"生活習慣"}/>
                {/*經常開車*/}
                <Picker data={OftenDriving} cols={1}
                        title={"經常開車"}
                        {...getFieldProps(FamilyMemberKey.OFTENDRIVING, {
                            rules: [{required: true}],
                        })}
                >
                    <XListItem arrow={"horizontal"}>經常開車</XListItem>
                </Picker>
                {/*經常運動*/}
                <Picker data={OftenExercising} cols={1}
                        title={"經常運動"}
                        {...getFieldProps(FamilyMemberKey.OFTENEXERCISING, {
                            rules: [{required: true}],
                        })}
                >
                    <XListItem arrow={"horizontal"}>經常運動</XListItem>
                </Picker>
                {/*經常吸煙*/}
                <Picker data={OftenSmoking} cols={1}
                        title={"經常吸煙"}
                        {...getFieldProps(FamilyMemberKey.OFTENSMOKING, {
                            rules: [{required: true}],
                        })}
                >
                    <XListItem arrow={"horizontal"}>經常吸煙</XListItem>
                </Picker>
                {/*經常飲酒*/}
                <Picker data={OftenDrinking} cols={1}
                        title={"經常飲酒"}
                        {...getFieldProps(FamilyMemberKey.OFTENDRINKING, {
                            rules: [{required: true}],
                        })}
                >
                    <XListItem arrow={"horizontal"}>經常飲酒</XListItem>
                </Picker>
            </View>
        );
    }

}

const styles = StyleSheet.create({

});

(5)不允許殘留注釋代碼,注釋掉的確認不用的代碼應當刪除

(6)關于注釋模板,復制以下代碼到IDE設置->Setting進行如下圖設置

注釋: $c$
* 時間: $a$ $b$
* @author XXX
image

在需要使用的注釋的地方,使用快捷鍵調出注釋,然后回車,打c回車或者Tab。具體使用如果有不明白的地方,百度“IDE設置Live Templates”

四、關于代碼編寫規范

(1)Props屬性一定要寫方法檢測

  static propTypes = {
    props: PropTypes.any,
    isAdd: PropTypes.bool,
    isShowRelationship: PropTypes.bool,
    gender: PropTypes.number,
    authStatus: PropTypes.number
  }

(2)如果元素內沒有子視圖,則標簽應該閉合

<LifeHabitView props={this.props}/>  //正確
<LifeHabitView props={this.props}></LifeHabitView>//錯誤

(3)內部變量使用let,常量不變值使用const,不要再使用var

    //請求接口
    const response = await AnXinServe.checkRepeatIdCard(params);
    if (response) {
        console.log("檢測家庭成員" + JSON.stringify(response));
        if (response.msg) {
            this.setState({errorMsg: response.msg.msg});
            this.setState({modalErrorVisiable: true});
            return;
        }
        if (response.familyMemberDTO) {
            let {insurantId, loginId} = response.familyMemberDTO;
            if (insurantId) {
                this.forms = forms;
                this.insurantId = insurantId;
                this.setState({isLoading: false});
                this.showCoverDialog();
                return;
            }
            if (loginId) {
                this.setState({isLoading: false});
                this.showIsMeDialog();
                return;
            }
            this.addMember(params);
        } else {
            this.addMember(params);
        }
    }

(4)盡量采用解構賦值的寫法獲取參數,不要使用xxxx.xxx.xxx的方式獲取參數

 let {insurantId, loginId} = response.familyMemberDTO;

(5)關于一對多選值,不要采用if else和switch方式獲取,盡量采用預設Map,然后從Map中獲取的方式拿到想要的值。

  _selectDefaultImage(rowData) {
    const relation = rowData.relation;
    const loginId = rowData.loginId;
    if (rowData.gender == 1 && loginId) { //投保人是男
      if (loginId) {
        return defaultImage.husband;
      } else {
        if (relation == 1) {
          return defaultImage.wife
        }
        if (relation == 2) {
          return defaultImage.father
        }
        if (relation == 3) {
          return defaultImage.mother
        }
        if (relation == 4 || relation == 6) {
          return defaultImage.gonggong_yuefu
        }
        if (relation == 5 || relation == 7) {
          return defaultImage.popo_yuemu
        }
        if (relation == 8) {
          return defaultImage.boy_bady
        }
        if (relation == 9) {
          return defaultImage.girl_baby
        }
      }
    } else {
      if (loginId) {
        return defaultImage.wife;
      } else {
        if (relation == 1) {
          return defaultImage.husband
        }
        if (relation == 2) {
          return defaultImage.father
        }
        if (relation == 3) {
          return defaultImage.mother
        }
        if (relation == 4 || relation == 6) {
          return defaultImage.gonggong_yuefu
        }
        if (relation == 5 || relation == 7) {
          return defaultImage.popo_yuemu
        }
        if (relation == 8) {
          return defaultImage.boy_bady
        }
        if (relation == 9) {
          return defaultImage.girl_baby
        }
      }
    }
    return defaultImage.husband;
  }
  /**
   * 作者:郭翰林
   * 時間:2018/8/1 0001 9:49
   * 注釋:設置頭像對應關系
   */
  setHeaderImageMap() {
    this.headerImageMap.set(0, require('../../resources/images/anXin/user_man.png'));
    this.headerImageMap.set(1, require('../../resources/images/anXin/user_women.png'));
    this.headerImageMap.set(2, require('../../resources/images/anXin/father.png'));
    this.headerImageMap.set(3, require('../../resources/images/anXin/mother.png'));
    this.headerImageMap.set(4, require('../../resources/images/anXin/gongong_or_yuefu.png'));
    this.headerImageMap.set(5, require('../../resources/images/anXin/popo_or_yuemu.png'));
    this.headerImageMap.set(6, require('../../resources/images/anXin/gongong_or_yuefu.png'));
    this.headerImageMap.set(7, require('../../resources/images/anXin/popo_or_yuemu.png'));
    this.headerImageMap.set(8, require('../../resources/images/anXin/boy_baby.png'));
    this.headerImageMap.set(9, require('../../resources/images/anXin/girl_baby.png'));
    this.headerImageMap.set(10, require('../../resources/images/anXin/anxin_car.png'));
    this.headerImageMap.set(11, require('../../resources/images/anXin/anxin_house.png'));
    this.headerImageMap.set(12, require('../../resources/images/anXin/anxin_cash.png'));
    this.headerImageMap.set(-1, require('../../resources/images/anXin/anxin_add.png'));
  }
    
  /**
   * 作者:郭翰林
   * 時間:2018/8/2 0002 9:56
   * 注釋:獲取顯示頭像
   */
  getItemHeaderImg(dataItem) {
    //是本人
    if (dataItem.relation < 2 && dataItem.relation !== -1) {
      if (dataItem.gender === 0) {
        //女
        return this.headerImageMap.get(1);
      } else {
        //男
        return this.headerImageMap.get(0);
      }
    } else {
      return this.headerImageMap.get(dataItem.relation);
    }
  }

(6)關于數組合并,不要采用for循環的方式合并,采用ES6推薦的方式合并數組

  /**
   * 作者:郭翰林
   * 時間:2018/7/31 0031 19:29
   * 注釋:獲取家庭成員列表
   * @returns {Promise<void>}
   */
  async getUserLists() {
    const params = {};
    params.joinEvalution = 1;
    params.loginId = await UserBridge.getLoginId();
    this.setState({isLoading: true});
    const response = await AnXinServe.familyMemberList(params);
    console.log("第三方保單-獲取保障對象" + JSON.stringify(response));
    this.setState({isLoading: false});
    if (response) {
      if (response.familyMemberDTOList) {
        let defaultDatas = [
          {relation: 10, name: "車輛"},
          {relation: 11, name: "房屋"},
          {relation: 12, name: "銀行卡"},
          {relation: -1, name: "添加新成員"},
        ];
        this.datas = [...response.familyMemberDTOList, ...defaultDatas];
        this.setState({listData: this.transDatas(-1)});
      }
    }
  }

(7)判空使用!==null的形式去判空不要使用變量本身去判空,否則變量為0會引起BUG

  async getUserInfo () {
    this.userInfo = await UserBridge.getUser()
    if (this.userInfo!==null) {
      const {gender} = this.userInfo
      if (gender) {
        this.setState({gender: gender})
      }
    }
  }

(8)state變量應當事先在constructor()中聲明,不涉及頁面刷新的變量不應寫入state中

  constructor (props) {
    super(props)
    this.state = {
      modalMeVisiable: false,
      modalCoverVisiable: false,
      modalErrorVisiable: false,
      isLoading: false,
      gender: 1,
      errorMsg: '',
    }
    this.insurantId = ''
    /**
     * 表單數據
     * @type {{}}
     */
    this.forms = {}
    this.joinEvalution = props.navigation.state.params.joinEvalution
  }

(9)盡量使用箭頭函數,不要使用this.XXXX.bind(this)的函數
普通函數中this對象的指向是可變的,但是在箭頭函數中,它是固定的

function foo() {
    setTimeout(() => {
    console.log('id:', this.id);
    }, 100);
}
var id = 21;
foo.call({ id: 42 });
// id: 42

箭頭函數可以讓this指向固定化,這種特性很有利于封裝回調函數

  var handler = {
    id: '123456',
    init: function() {
      document.addEventListener('click',
        event => this.doSomething(event.type), false);
    },
    doSomething: function(type) {
      console.log('Handling ' + type + ' for ' + this.id);
    }
  };

上面代碼的init方法中,使用了箭頭函數,這導致這個箭頭函數里面的this,總是指向handler對象。否則,回調函數運行時,this.doSomething這
一行會報錯。
this指向的固定化,并不是因為箭頭函數內部有綁定this的機制,實際原因是箭頭函數根本沒有自己的this,導致內部的this就是外層代碼塊
的this。正是因為它沒有this,所以也就不能用作構造函數。
(10)使用ES6的語法的導出和導入即export和import
(11)關于常量定義不建議在常量類中書寫屬性方法,如果需要定義方法最好使用類引用Static函數的方式。

import { NativeModules, Platform, StatusBar } from 'react-native'

export default class Common {

  static async getTopOfSafeArea () {
    if (Platform.OS === 'ios') {
      return await NativeModules.CommonUtilBridge.getTopOfSafeArea()
    } else {
      return StatusBar.currentHeight
    }
  }

  static async getTopEdgeOfSafeArea () {
    if (Platform.OS === 'ios') {
      return await NativeModules.CommonUtilBridge.getTopEdgeOfSafeArea()
    } else {
      return StatusBar.currentHeight
    }
  }

  static async getBottomOfSafeArea () {
    if (Platform.OS === 'ios') {
      return await NativeModules.CommonUtilBridge.getBottomOfSafeArea()
    } else {
      return 0
    }
  }

  static async addPolicyToWallet (policyId, callback) {
    if (Platform.OS === 'ios') {
      await NativeModules.CommonUtilBridge.addPolicyToWallet(policyId, callback)
    }
  }

  static async uploadPoilcy (file, callback) {
    await NativeModules.CommonUtilBridge.uploadPolicy(file, callback)
  }
}
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,702評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,143評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,553評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,620評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,416評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,940評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,024評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,170評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,709評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,597評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,784評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,291評論 5 357
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,029評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,407評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,663評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,403評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,746評論 2 370

推薦閱讀更多精彩內容