美文网首页
React Native 开发规范

React Native 开发规范

作者: RmondJone | 来源:发表于2018-08-10 13:01 被阅读0次

    一、关于命名

    (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)
      }
    }
    

    相关文章

      网友评论

          本文标题:React Native 开发规范

          本文链接:https://www.haomeiwen.com/subject/bbpkbftx.html