Uninote
Uninote

#####编写目的

  • 为规范软件开发人员的代码编写提供参考依据和统一标准

#####文档约定

  • [强制]表示必须按要求执行
  • [推荐]表示建议按要求执行
  • [推荐偏强制]自己理解执行

#####参考文献

#####基本规范

  • [强制]每个文件只包含一个React组件
  • [强制]React Native 和 React 都要尽可能的使用ES6语法
  • [强制]console在调试时写、调试完立即删除
  • [强制]不允许未经定义的常量直接出现在代码中
  • [强制]项目目录应按功能进行创建及维护
  • [建议偏强制]两段功能或业务相同或类似的代码不应该出现两次
  • [建议]使用第三方插件时应仔细阅读官方文档的 Readme.md、issue、最新提交代码的时间、充分了解可能会出现的问题及解决办法、节省调试时间、降低开发难度
  • [建议]将接口地址按功能划分归类分开维护、后期接口升级等便于维护
  • [建议]不要使用一个常量类维护所有常量、应该按常量功能进行归类、分开维护; 大而全的常量类、非得使用查找功能才能定位到修改的常量、不利于理解和维护

#####目录规范

  • 以下目录结构示例中只展示js与静态资源、不包含原生代码
    ├── index.js
    ├── App.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
  • 通用的组件放在Component文件夹
  • 调用原生android/ios都写在同一个.js文件内

#####代码顺序 ######import引用顺序

React
ReactNative
Redux
ReactRedux
第三方库
自定义组件
图片
公共样式
业务组件及其样式
Actions
  • [强制]import顺序一般如下并且分组; 对组件引用、变量引用、需遵从以下方式
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'
  • [推荐]对组件引用、变量初始化等、在整个页面或组件内未使用、因去除相关代码
  • [推荐]某些全局变量请不要使用global、需新建文件进行导出引用; NetUtil.get(global.url + “”)
  • [推荐]render() 函数代码过长时、请适当进行拆分、拆分为”页面内组件“提高可读性; render()函数代码行请勿超过八十行、超过之后、请自行进行拆

######方法函数顺序

  • 方法的顺序如下
getDefaultProps
getInitialState
componentWillMount
componentDidMount
componentWillReceiveProps
shouldComponentUpdate
componentWillUpdate
componentDidUpdate
componentWillUnmount
other method ...
render

#####命名规范

  • [强制]文件夹命名使用大驼峰命名法 比如: Home、User、Set
  • [强制]文件命名要使用大驼峰命名法 比如: HomePage.js、UserPage.js
  • [强制]React Native 中如果仅有 android/ios 其中一端的功能、在文件的尾加 .android/.ios; 比如 KeyBoard.android.js、KeyBoard.ios.js
  • [强制]杜绝 1、2、3、one、two、three 之类名称; 用功能或者是模块来命名
  • [强制]函数命名、事件处理函数的命名采: 用 “handle” + “EventName” 的方式来命名; 事件函数作为属性时的命名: on +EventName 与 handle 对应 <Component onClick={this.handleClick} />
  • [强制]代码中用于页面展示处理UI的组件、命名以Page结尾、自定义组件命名以Component结尾 如: LoginPage、ButtonComponent
  • [强制]变量命名定义规则如
let sUserName = 'xxx'; // 字符串 s开头
let nAge = 20; // 数字 n开头
let isRequestSuccess = false; let hasProperty = false; // Boolean 使用 is、has等
let uPaperName = undefined; // undefined u开头
let aMyArray = []; // 数组 a开头
let oMyObject = {}; // 对象 o开头
  • [推荐]命名取词: 变量名应当使用名词、boolean类型的应当使用 is、has 等开头表示其类型、函数名应当用动宾短语、类名应当用名词

#####结构规范 ######缩进

  • [强制]使用 4 个空格做为一个缩进层级; 不允许使用 2 个空格 或 tab 字符; switch 下的 case 和 default 必须增加一个缩进层级
// good
switch (variable) {

    case '1':
        // do...
        break;

    case '2':
        // do...
        break;

    default:
        // do...
}

// bad
switch (variable) {

case '1':
    // do...
    break;

case '2':
    // do...
    break;

default:
    // do...
}

######空格

  • [强制]二元运算符两侧必须有一个空格; 一元运算符与操作对象之间不允许有空格
let a = !arr.length;
a++;
a = b + c;
  • [强制]用作代码块起始的左花括号 { 前必须有一个空格
// good
if (condition) {
    // do...
}

while (condition) {
    // do...
}

function funcName() {
    // do...
}

// bad
if (condition){
    // do...
}

while (condition){
    // do...
}

function funcName(){
    // do...
}
  • [强制]if / else / for / while / function / switch / do / try / catch / finally 关键字后、必须有一个空格
// good
if (condition) {
}

while (condition) {

}

(function () {

})();

// bad
if(condition) {

}

while(condition) {

}

(function() {

})();
  • [强制]在对象创建时、属性中的、 : 之后必须有空格、 : 之前不允许有空格
// good
var obj = {
    a: 1,
    b: 2,
    c: 3
};

// bad
var obj = {
    a : 1,
    b:2,
    c :3
};
  • [强制]函数声明、具名函数表达式、函数调用中; 函数名和 ( 之间不允许有空格
// good
function funcName() {
}

var funcName = function funcName() {
};

funcName();

// bad
function funcName () {
}

var funcName = function funcName () {
};

funcName ();
  • [强制] , 和 ; 前不允许有空格; 如果不位于行尾、 , 和 ; 后必须跟一个空格
// good
callFunc(a, b);

// bad
callFunc(a , b) ;
  • [强制] 在函数调用、函数声明、括号表达式、属性访问、if / for / while / switch / catch 等语句中; () 和 [] 内紧贴括号部分不允许有空格
// good
callFunc(param1, param2, param3);

save(this.list[this.indexes[i]]);

needIncream && (variable += increament);

if (num > list.length) {

}

while (len--) {

}

// bad
callFunc( param1, param2, param3 );

save( this.list[ this.indexes[ i ] ] );

needIncreament && ( variable += increament );

if ( num > list.length ) {

}

while ( len-- ) {

}
  • [强制] 单行声明的数组与对象、如果包含元素,{} 和 [] 内紧贴括号部分不允许包含空格; 声明包含元素的数组与对象、只有当内部元素的形式较为简单时、才允许写在一行; 元素复杂的情况、还是应该换行书写
// good
var arr1 = [];
var arr2 = [1, 2, 3];
var obj1 = {};
var obj2 = {name: 'obj'};
var obj3 = {
    name: 'obj',
    age: 20,
    sex: 1
};

// bad
var arr1 = [ ];
var arr2 = [ 1, 2, 3 ];
var obj1 = { };
var obj2 = { name: 'obj' };
var obj3 = {name: 'obj', age: 20, sex: 1};
  • [强制]行尾不得有多余的空格

######换行

  • [强制]每个独立语句结束后必须换行
  • [强制]每行不得超过 120 个字符; 超长的不可分割的代码允许例外、比如复杂的正则表达式、长字符串不在例外之列
  • [强制]运算符处换行时、运算符必须在新行的行首
// good
if (user.isAuthenticated()
    && user.isInRole('admin')
    && user.hasAuthority('add-admin')
    || user.hasAuthority('delete-admin')
) {
    // Code
}

var result = number1 + number2 + number3
    + number4 + number5;


// bad
if (user.isAuthenticated() &&
    user.isInRole('admin') &&
    user.hasAuthority('add-admin') ||
    user.hasAuthority('delete-admin')) {
    // Code
}

var result = number1 + number2 + number3 +
    number4 + number5;
  • [强制]在函数声明、函数表达式、函数调用、对象创建、数组创建、for 语句等场景中,不允许在 , 或 ; 前换行
// good
var obj = {
    a: 1,
    b: 2,
    c: 3
};

foo(
    aVeryVeryLongArgument,
    anotherVeryLongArgument,
    callback
);


// bad
var obj = {
    a: 1
    , b: 2
    , c: 3
};

foo(
    aVeryVeryLongArgument
    , anotherVeryLongArgument
    , callback
);
  • [建议] 不同行为或逻辑的语句集、使用空行隔开、更易阅读
// 仅为按逻辑换行的示例,不代表setStyle的最优实现
function setStyle(element, property, value) {
    if (element == null) {
        return;
    }

    element.style[property] = value;
}
  • [建议]在语句的行长度超过 120 时; 根据逻辑条件合理缩进
// 较复杂的逻辑条件组合、将每个条件独立一行、逻辑运算符放置在行首进行分隔、或将部分逻辑按逻辑组合进行分隔
// 建议最终将右括号 ) 与左大括号 { 放在独立一行、保证与 `if` 内语句块能容易视觉辨识
if (user.isAuthenticated()
    && user.isInRole('admin')
    && user.hasAuthority('add-admin')
    || user.hasAuthority('delete-admin')
) {
    // Code
}

// 按一定长度截断字符串、并使用 + 运算符进行连接
// 分隔字符串尽量按语义进行、如不要在一个完整的名词中间断开
// 特别的、对于 HTML 片段的拼接、通过缩进、保持和 HTML 相同的结构
var html = '' // 此处用一个空字符串、以便整个 HTML 片段都在新行严格对齐
    + '<article>'
    +     '<h1>Title here</h1>'
    +     '<p>This is a paragraph</p>'
    +     '<footer>Complete</footer>'
    + '</article>';

// 也可使用数组来进行拼接、相对 `+` 更容易调整缩进
var html = [
    '<article>',
        '<h1>Title here</h1>',
        '<p>This is a paragraph</p>',
        '<footer>Complete</footer>',
    '</article>'
];
html = html.join('');

// 当参数过多时、将每个参数独立写在一行上、并将结束的右括号 ) 独立一行
// 所有参数必须增加一个缩进
foo(
    aVeryVeryLongArgument,
    anotherVeryLongArgument,
    callback
);

// 也可以按逻辑对参数进行组合
// 最经典的是 baidu.format 函数、调用时将参数分为“模板”和“数据”两块
baidu.format(
    dateFormatTemplate,
    year, month, date, hour, minute, second
);

// 当函数调用时、如果有一个或以上参数跨越多行、应当每一个参数独立一行
// 这通常出现在匿名函数或者对象初始化等作为参数时; 如 `setTimeout` 函数等。
setTimeout(
    function () {
        alert('hello');
    },
    200
);

order.data.read(
    'id=' + me.model.id,
    function (data) {
        me.attchToModel(data.result);
        callback();
    },
    300
);

// 链式调用较长时采用缩进进行调整
$('#items')
    .find('.selected')
    .highlight()
    .end();

// 三元运算符由3部分组成、因此其换行应当根据每个部分的长度不同、形成不同的情况
var result = thisIsAVeryVeryLongCondition
    ? resultA : resultB;

var result = condition
    ? thisIsAVeryVeryLongResult
    : resultB;

// 数组和对象初始化的混用、严格按照每个对象的 `{` 和结束 `}` 在独立一行的风格书写
var array = [
    {
        // ...
    },
    {
        // ...
    }
];

######语句

  • [强制]不得省略语句结束的分号
  • [强制]在 if / else / for / do / while 语句中]、即使只有一行、也不得省略块 {...}
// good
if (condition) {
    callFunc();
}

// bad
if (condition) callFunc();
if (condition)
    callFunc();
  • [强制]函数定义结束不允许添加分号
// good
function funcName() {
}

// bad
function funcName() {
};

// 如果是函数表达式、分号是不允许省略的
var funcName = function () {
};

#####注释规范 ######顶层文件注释

  • 顶层注释用于告诉不熟悉这段代码的读者这个文件中包含哪些东西、应该提供文件的大体内容、它的作者、依赖关系、兼容性信息
/**
 * @file LsOrRwPreview
 * @date 2018/12/20 13:11
 * @author Administrator
 * @lastModify Administrator 2018/12/20 13:11
 */

######构造器函数

  • @class 别名:@constructor
  • 标明函数是一个构造器函数、意味着需要使用 new 关键字来返回一个实例、即使用 new 关键字实例化
/**
 * Create new Point
 * @class
 */
function Point {
    // TODO:
}
let point = new Point();

######类的注释

  • @classdesc
  • 标签用于为类提供一个描述、这样和构造函数的描述区分开来; @classdesc标签应该与 @class (或@constructor)标签结合使用
// Example 1
/**
 * Create new MyClass
 * @class
 * @classdesc This is MyClass description
 * @params {string} className - 班级名称
 * @params {string} classDescript - 班级描述
 */
function MyClass(className, classDescript) {
    this.className = className;
    this.classDescript = classDescript;
}
// Example 2
/**
 * Create new MyClass
 * @class
 * @classdesc This is MyClass description
 */
class MyClass {
    // TODO:
}
  • 当使用 extends 关键字来扩展一个现有的类的时候; 可以使用 @augments (或 @extends) 标签
/**
 * Class representing a dot.
 * @class
 * @classdesc This is HerClass description
 * @extends MyClass
 */
class HerClass extends MyClass {
    // TODO:
}

######函数注释

  • @param 标签提供了对某个函数的参数的各项说明、包括参数名、参数数据类型、描述等; @param {变量类型} 变量名 - 变量描述 ex: @params {string | Number}
  • @callback 描述一个回调函数
  • @returns 描述一个函数的返回值; 语法和@param类似
/**
 * Send a post Request
 * @param {string} url - 请求地址
 * @param {string} method - 请求方式
 * @param {Object} body - 请求所需参数
 * @callback successCallBack-requestSuccessCallBack - 请求成功的回调
 * @callback errorCallBack-requestErrorCallBack - 请求失败的回调
 * @returns {Promise.<*>}
 */
const requestUrl = async (url, method, body, successCallBack, errorCallBack) => {
    reurn new Promise...
};

#####页面编写

  • [强制]代码中初始化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
    };
  • [强制]代码中创建数组或对象使用以下方式
const user = {
        name:'time',
        sex:'男',
        age:25,
    };
const itemArray = ['0','1','2',3,{name:'25',age:'男'}];
  • [强制]代码中函数绑定this、强制使用箭头函数; 注: 除组件原有方法、其他自定义函数命名时、需使用箭头函数
// 系统组件生命周期方法
constructor(props) {
    super(props);
};
// 自定义方法
goMainPage=()=> {
    console.log(this); // 对于箭头函数来说、并没有自己的 this 它的 this 将始终指向让它生效的对象、即它的外部调用者
};
  • [强制]代码中一些网络数据初始化、配置信息、推荐在此生命周期进行初始化
componentWillMount
  • [强制]代码中使用定时器或者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);
};
  • [推荐]关于平台区分这是创建一个 demo 默认的代码、要比三目运算符好一些
const instructions = Platform.select({
  ios: 'Press Cmd+R to reload,\n' +
    'Cmd+D or shake for dev menu',
  android: 'Double tap R on your keyboard to reload,\n' +
    'Shake or press menu button for dev menu',
});

#####面向组件开发

  • [推荐]开发react、react-native项目时应遵循此开发规范; 组件化的本质、实就是面向对象的设计思想; 组件化可以对应于 一个类、每个类都对外输出不变的接⼝、只要接⼝不变、类与类间的通讯可以根据接⼝进行、由此不同组件间的耦合度就降低了; 同时复杂的类可以通过若干个简单的类组合而成、这样一来、不但可以提高组件的重用性、同时通过组合的思想来设计复杂的控件、 也极大的降低了复杂控件的设计难度

avatar


如图所示
AssignNormalHomeWork.js,
AssignSpecialHomeWork.js,
FastAssignHomePage.js
都有选择日期、选择时间、选择班级的操作
我们将这三个view抽离成三个组件、界面无需关心组件如何实现、只需按照约定传递对应的值即可、选择后组件会将结果传递回去
如果以后需要改日期选择的样式、只需改动组件、而非像没有抽离成组件之前、改动三个界面甚至更多
这只是一个简单的组件化编程示例、可能还会遇到将一个复杂的组件抽离成多个子组件等等业务场景、大同小异
  • 简述目录结构、如图所示、这是爱老师教师端作业版块下布的置作业模块、在assign目录下创建当前业务模块所需的component、page、util、这样目录结构一目、修改维护也更方便

#####样式规范

  • [强制]当组件使用样式属性达到三个或者三个以上时、必须使用StyleSheet来创建样式属性并进行引用
const styles = StyleSheet.create({
     container: {
         flex: 1,
         justifyContent: 'center',
         alignItems: 'center',
         backgroundColor: '#F5FCFF',
         marginTop:Common.scaleSize(10)
     }
 });
  • [推荐]当使用单一属性、或者全局样式属性时、推荐使用公共样式类
// StyleCommon.js
 export default {
     topColor:{
         backgroundColor: '#3A3D42',
     },
     mainView:{
         backgroundColor: '#12141B',
     },
 }`在这里插入代码片`
  • [推荐]当使用多个state或者props值时、推荐使用以下方式
const {size, dotRadius, color} = this.props;
const {maxNumber, minNumber} = this.state;

#####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文件、内容包括测试、正式环境等相关配置文件以及注意事项

#####日志管理

  • [推荐]代码中过多使用console.log()会消耗性能、推荐去除不必要的日志输入代码
  • [强制]在入口文件添加以下代码
if (!__DEV__) {
       global.console = {
         info: () => {},
         log: () => {},
         warn: () => {},
         error: () => {},
       };
 }

说明: 可以在发布时屏蔽掉所有的console调用; React Native中有一个全局变量__DEV__用于指示当前运行环境是否是开发环境; 我们可以据此在正式环境中替换掉系统原先的console实现

Jarsgner签名

RN报错汇总

点赞(0) 阅读(1) 举报
目录
标题