美文网首页React Native
React Native 开发规范

React Native 开发规范

作者: yuzhiyi_宇 | 来源:发表于2018-03-17 22:30 被阅读23次

React Native 开发规范

一、编码规范

  • (一) 命名风格
  • (二) 常量定义
  • (三) 变量定义
  • (四) 对象定义
  • (五) 数组定义
  • (六) 字符串使用
  • (七) 函数定义及使用
  • (八) 比较运算符 & 等号
  • (九) 循环体
  • (十) 类型转换
  • (十一) 代码格式
  • (十二) package.json
  • (十三) 控制语句
  • (十四) 日志管理

二、页面编写规范

  • (一) state
  • (二) props
  • (三) 监听器
  • (四) 无状态组件
  • (五) 高阶组件

三、性能优化

四、安全规范

附录1、参考文献

一、编码规范

(一) 命名风格

  1. 【强制】代码中的命名均不能以下划线或美元符号开始,也不能以下划线或美元符号结束。
    反例: _name / _name / $name / name_ / name$ / name_
  2. 【强制】代码中的命名严禁使用拼音与英文混合的方式,更不允许直接使用中文的方式。
    说明:正确的英文拼写和语法可以让阅读者易于理解,避免歧义。注意,即使纯拼音命名方式也要避免采用。
    正例: alibaba / taobao / youku / hangzhou 等国际通用的名称,可视同英文。
    反例: DaZhePromotion [ 打折 ] / getPingfenByName() [ 评分 ] / let 某变量 = 3
  3. 【强制】类名使用 UpperCamelCase 风格。
    正例: LoginPage
  4. 【强制】方法名、参数名、成员变量、局部变量都统一使用 lowerCamelCase 风格,必须遵从驼峰形式。
    正例: localValue / getHttpMessage() / inputUserId
  5. 【强制】常量命名全部大写,单词间用下划线隔开,力求语义表达完整清楚,不要嫌名字长。
    正例: MAX_STOCK_COUNT
    反例: MAX_COUNT
  6. 【强制】文件夹命名统一小写。
    正例: components // 存放一些组件

(二) 常量定义

  1. 【推荐】对所有常量,对象的引用,推荐使用 const,不要使用 var 或者 let。
  2. 【强制】不允许任何魔法值 ( 即未经预先定义的常量 ) 直接出现在代码中。

反例:

    if (nameKeyValue === 1) {
        // todo
    }
  1. 【强制】不要使用一个常量类维护所有常量,按常量功能进行归类,分开维护。
    说明: 大而全的常量类,非得使用查找功能才能定位到修改的常量,不利于理解和维护。
    正例: 标识字段相关常量放在 common/Defines.js 下 ; 系统配置相关常量放在类 configs/index.js 下。

(三) 变量定义

  1. 【推荐】需要引用可变动的变量,对象,建议使用 let 代替 var。
    说明: 注意 var,let 的作用域。
  2. 【强制】所有变量先定义,后使用。
  3. 【强制】所有变量声明时赋予一个默认值。

(四) 对象定义

  1. 【推荐】使用字面量语法来创建对象。

正例:

    let item = {};

反例:

    let item = new Object();
  1. 【强制】不要使用[保留字]作为函数名、属性名、变量名。

正例:

    var superman = {
        defaults: { clark: 'kent' },
        hidden: true
    };

反例:

    var superman = {
        default: { clark: 'kent' },
        private: true
    };
  1. 推荐使用扩展运算符[...]复制对象。

正例:

    const original = { a: 1, b: 2 };
    const copy = { ...original, c: 3 };

反例:

    const original = { a: 1, b: 2 };
    const copy = Object.assign(original, { c: 3 });

(五) 数组定义

  1. 【推荐】使用直接量创建数组。

正例:

    let items = [];

反例:

    let items = new Array();
  1. 【推荐】向数组增加元素时使用 Array#push 来替代直接赋值。

正例:

    let someStack = [];
    someStack.push('abc');

反例:

    let someStack = [];
    someStack[someStack.length] = 'abc'
  1. 【推荐】使用扩展运算符[...]复制数组。

正例:

    const itemsCopy = [...items];

反例:

    const len = items.length;
    const itemsCopy = [];
    let i;
    for (i = 0; i < len; i++) {
        itemsCopy[i] = items[i];
    }
  1. 【推荐】使用 Array.from 将类数组对象转换成数组。

正例:

    let arrayLike = {  
        '0': 'a',  
        '1': 'b',  
        '2': 'c',  
        length: 3  
    }; 
    let args = Array.from(arguments); // ['a','b','c']

(六) 字符串使用

1.【推荐】使用单引号 '' 包裹字符串。

正例:

    let name = 'Bob Parr';

反例:

     let name = "Bob Parr";

2.【推荐】超过 100 个字符的字符串应该使用连接符写成多行。

正例:

    let errorMessage = 'This is a super long error that was thrown
    because ' +
        'of Batman. When you stop to think about how Batman had anything
    to do ' +
        'with this, you would get nowhere fast.';

反例:

    let errorMessage = 'This is a super long error that was thrown
    because of Batman. When you stop to think about how Batman 
    had anyt hing to do with this, you would get nowhere fast.';

    let errorMessage = 'This is a super long error that was thrown
    because \
    of Batman. When you stop to think about how Batman had anything to
    do \
    with this, you would get nowhere \
    fast.';

(七) 函数定义及使用

  1. 【强制】不要在一个非函数代码块(if、while 等)中声明一个函数,把那个函数赋给一个变量。
  2. 【强制】不要把参数命名为 arguments,这将取代函数作用域内的arguments 对象。

正例:

    nope(name, options, args) {
        // todo
    }

反例:

    nope(name, options, arguments)) {
        // todo
    }

(八) 比较运算符 & 等号

  1. 【推荐】优先使用 === 和 !== 而不是 == 和 !=。
  2. 【推荐】使用快捷方式,条件表达式例如 if 语句通过抽象方法 ToBoolean 强制计算它们的表达式并且总是遵守下面的规则:
    1 ) 对象 被计算为 true
    2 ) Undefined 被计算为 false
    3 ) Null 被计算为 false
    4 ) 布尔值 被计算为 布尔的值
    5 ) 数字 如果是 +0、-0 或 NaN 被计算为 false,否则为 true
    6 ) 字符串 如果是空字符串 '' 被计算为 false,否则为 true

正例:

    if (collection.length) {
        // todo
    }

    if (name) {
        // todo
    }

反例:

    if (name !== '') {
        // todo
    }

    if (collection.length > 0) {
        // todo
    }

(九) 循环体

  1. 【强制】循环体 for( in ) 的性能损失是 for( of ) 或者 for(;;) 的 10 倍,所以尽量使用 for( of ) ,如果需要 index 的才使用 for(;;) 。
    说明: Object 无法 .length ,所以不能改成相应的 for(;;) ,只能用 for( in ) 。
    Array 是可以 .length 的,所以使用 for( of ) 或者 for(;;) 皆可。

(十) 类型转换

  1. 【强制】使用 parseInt 转换数字时带上类型转换的基数。

正例:

    let inputValue = '4';
    let val = parseInt(inputValue, 10);
  1. 【推荐】转成布尔型,推荐使用双取反。
    let age = 0;
    let hasAge = !!age;

(十一) 代码格式

  1. 【强制】大括号的使用约定。如果是大括号内为空,则简洁地写成{}即可,不需要换行 ; 如果是非空代码块则:
    1 ) 左大括号前不换行。
    2 ) 左大括号后换行。
    3 ) 右大括号前换行。
    4 ) 右大括号后还有 else 等代码则不换行 ; 表示终止的右大括号后必须换行。
  2. 【强制】 左小括号和字符之间不出现空格 ; 同样,右小括号和字符之间也不出现空格。详见
    第 5 条下方正例提示。
    反例: if (空格 a == b 空格)
  3. 【强制】 if / for / while / switch / do 等保留字与括号之间都必须加空格。
  4. 【强制】任何二目、三目运算符的左右两边都需要加一个空格。
    说明:运算符包括赋值运算符=、逻辑运算符&&、加减乘除符号等。
  5. 【强制】采用 4 个空格缩进,禁止使用 tab 字符。
    说明:如果使用 tab 缩进,必须设置 1 个 tab 为 4 个空格。
    正例: ( 涉及 1-5 点 )
    sayHello() {
        const say = 'hello';
        // 运算符的左右必须有一个空格
        const flag = 0;
        // 关键词 if 与括号之间必须有一个空格,括号内的 f 与左括号,0 与右括号不需要空格
        if (flag === 0) {
            console.log(say);
        }
        // 左大括号前加空格且不换行;左大括号后换行
        if (flag === 1) {
            console.log('world');
            // 右大括号前换行,右大括号后有 else,不用换行
        } else {
            console.log('ok');
        }
    }
  1. 【强制】注释的双斜线与注释内容之间有且仅有一个空格。

正例:

    // 这是示例注释,请注意在双斜线之后有一个空格
    let hello = 'Hello';
  1. 【强制】单行字符数限制不超过 120 个,超出需要换行,换行时遵循如下原则:
    1 ) 第二行相对第一行缩进 4 个空格,从第三行开始,不再继续缩进,参考示例。
    2 ) 运算符与下文一起换行。
    3 ) 方法调用的点符号与下文一起换行。
    4 ) 方法调用时,多个参数,需要换行时,在逗号后进行。
    5 ) 在括号前不要换行,见反例。

正例:

    const path = Path()
            .moveTo(0, -redius/2)
            .arc(0, redius, 1)
            .arc(0, -redius, 1)
            .close();

反例:

    // 超过 120 个字符的情况下,不要在括号前换行
    const path = Path() .moveTo(0, -redius/2).arc(0, redius, 1)...arc
        (0, -redius, 1) .close();

    // 参数很多的方法调用可能超过 120 个字符,不要在逗号前换行
    method(args1, args2, args3, ...
        , argsX);
  1. 【强制】方法参数在定义和传入时,多个参数逗号后边必须加空格。
    正例:下例中实参的" a ",后边必须要有一个空格。
    method("a", "b", "c");
  2. 【推荐】不同逻辑、不同语义、不同业务的代码之间插入一个空行分隔开来以提升可读性。
    说明:没有必要插入多个空行进行隔开。

(十二) package.json

  1. 【强制】在使用 npm 或者 yarn 获取资源时,必须在命令末尾添加 --save。
    说明: 使用此命令会把使用的第三方相关信息写入到 package.json,这样,其他成员在下载或者更新代码后使用 npm i(或 npm install),就可以下载最新的 npm 库,若不加 --save,执行 npm i 的时候就不会下载,其他成员运行项目可能会报错,此时需要分析查看报错信息进行重新的 npm install xxx。
  2. 【强制】使用 git 或者 svn 进行代码版本管理时,不要上传 node_module文件(进行忽略)。
    说明: 使用 package.json 进行包管理,下载或更新代码后,只需要执行 npm i,当有修改 npm 包,建议进行版本管理,上传到私有的github仓库。使用私有地址时,使用如下命令:
    npm i "git+私有仓库地址" --save
  3. 【强制】使用第三方或拉取新仓库时,第一步使用 npm i 。
    说明:
    1 ) 检查版本是否冲突
    2 ) 更新node_modules
  4. 【推荐】在使用 npm 或者 yarn 获取资源时,推荐不在命令行后添加 -g。
    说明: 此命令可以让此资源包在根目录进行获取(全局安装),不利于资源管理。
  5. 【强制】每个项目必须配置一个 READMA.md 文件,内容包括测试,正式环境等相关配置文件以及注意事项。
  6. 【推荐】安装 npm 包时,推荐 ~ 来标识版本号,在需要稳定版本的时候去掉 package.json 中的 ^ 或 ~ 符号。
    说明:~ 和 ^ 的作用和区别: ~ 会匹配最近的小版本依赖包,比如 ~1.2.3会匹配所有 1.2.x 版本,但是不包括 1.3.0。
    ^ 会匹配最新的大版本依赖包,比如 ^ 会匹配所有 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. 【推荐】表达异常的分支时,少用 if-else 方式 ,这种方式可以改写成:
    正例:
    if (condition) {
        ...
        return obj;
    }   
    // 接着写 else 的业务逻辑代码;

说明:如果非得使用 if()...else if()...else... 方式表达逻辑,【强制】避免后续代码维
护困难,请勿超过 3 层。
正例:超过 3 层的 if-else 的逻辑判断代码可以使用卫语句、策略模式、状态模式等来实现,
其中卫语句示例如下:

    today() {
        if (this.isBusy()) {
            console.log('change time.');
            return;
        }
        if (this.isFree()) {
            console.log('go to travel.');
            return;
        }
        console.log('stay at home to learn Alibaba Java Coding Guidelines.');
        return;
    }
  1. 【推荐】除常用方法(如 getXxx/isXxx )等外,不要在条件判断中执行其它复杂的语句,将复杂逻辑判断的结果赋值给一个有意义的布尔变量名,以提高可读性。
    说明:很多 if 语句内的逻辑相当复杂,阅读者需要分析条件表达式的最终结果,才能明确什么样的条件执行什么样的语句,那么,如果阅读者分析逻辑表达式错误呢?

正例:

    // 伪代码如下
   const isUserExisted = (user != null && user.id >= 0)  && (...) || (...);
    if (isUserExisted) {
        ...
    }

反例:

    if ((user != null && user.id >= 0)  && (...) || (...)) {
        ...
    }

5.【推荐】避免采用取反逻辑运算符。
说明:取反逻辑不利于快速理解,并且取反逻辑写法必然存在对应的正向逻辑写法。
正例: 使用 if (x < 628) 来表达 x 小于 628。
反例: 使用 if (!(x >= 628)) 来表达 x 小于 628。

(十四) 日志管理

1.【推荐】代码中过多使用 console.log 会消耗性能,推荐去除不必要的日志输入代码。
2.【强制】在入口文件添加一下代码。
说明: 可以在发布时屏蔽掉所有的 console.* 调用。React Native 有一个全局变量 Dev 用来指示当前运行环境是否是开发环境。我们可以据此在正式环境中替换掉系统原先的 console 实现。

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

这样打包发布时,所有的控制台语句就会被自动替换成空函数,而在调试时它们仍然会被正常调用。

二、页面编写规范

(一) state

1.【强制】当页面组件不需要跟随动态值重新 render 从而更新界面的时候,不要把值动态存储在 state 里。

正例:

    constructor(props) {
        super(props);
        this.inputText = '';
    }

    onChangeText = (text) => {
        this.inputText = text;
    }

    render() {
        return (
            <View>
                <TextInput
                    onChangeText={this.onChangeText}
                />
            </View>
        );
    }

反例:

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

    onChangeText = (text) => {
        this.setState({
            inputText: text
        });
    }

    render() {
        return (
            <View>
                <TextInput
                    onChangeText={this.onChangeText}
                />
            </View>
        );
    }
  1. 【推荐】组件内部的 state 尽量少,将其推到系统边缘处,方便统一管理,组件通过接收 props 更新视图。
  2. 【推荐】当使用多个 state时,推荐使用解构,统一写在方法开头。

正例:

    const {
        text,
        visible
    } = this.state;

(二) props

1.【推荐】推荐使用 props 更新子组件试图,而不是 通过 ref 获得子组件实例操作子组件的方式。
2.【强制】不需要改变的 props,要保持引用地址唯一。PropTypes 类型是 funcation,需要绑定this,不需要传递额外的参数,强制使用箭头函数的方式,需要传参数的时候推荐使用 bind 方式,style 强制使用 StyleSheet 来创建样式并进行引用。

正例:

class Login extends PureComponent {

    onPress = () => {

    }

    render() {
        return (
            <TouchableOpacity
                style={styles.button}
                onPress={this.onPress}>
                <Text style={styles.text}>
                    我要出租
                </Text>
            </TouchableOpacity>
        );
    }
}

const styles = StyleSheet.create({
    button: {
        backgroundColor: 'rgba(24,190,188,1.0)',
        justifyContent: 'center',
        alignItems: 'center'
    },
    text: {
        color: 'white',
        fontSize: 16
    }
});

  1. 【推荐】当使用多个 props 时,推荐使用解构,统一写在方法开头。

正例:

    const {
        size,
        color
    } = this.props;

(三) 监听器

1.【强制】代码中使用监听器,必须在组件卸载的时候进行销毁或者卸载。

正例:

    const listeners = {};
    class Text extends Component {
        receive = () => {
        }

        componentDidMount() {
            this.timer = setTimeout( () => {
            });
            this.addReceiveCustomMsgListener(this.receive);
       }
    
        addListener(cb) {
            listeners[cb] = DeviceEventEmitter.addListener(
                (message) => {
                    cb(message);
            });
        }

        removeListener(cb) {
            if (!listeners[cb]) {
                return;
            }
            listeners[cb].remove();
            listeners[cb] = null;
       }

       componentWillUnmount() {
            this.timer && clearTimeout(this.timer);
            this.removeListener(this.receive);
       }
    }

(四) 无状态组件

1.【推荐】当不需要状态 state 的组件,推荐使用无状态组件。

正例:

    const Title = (props) => (
        <Text>
           {props.title}
        </Text>
    )
    
    Title.propTypes = {title: PropTypes.string}
    Title.defaultProps = {title: 'stateless component'}

(五) 高阶组件

  1. 【推荐】组件类有共享逻辑,推荐抽象成高阶组件(Hoc,Higher-order Component)。

正例:

   const LoginPleaseMixin = (ComposedComponent, LoginPlease) => {

        return class extends PureComponent {
            render() {
                const {
                    user
                } = this.props;
                if (user.isLogin) {
                    return (
                        <ComposedComponent
                            {...this.props}
                        />
                    );
                } else {
                    return (
                        <LoginPlease
                            {...this.props}
                        />
                    );
                }
            }
        };
    };
    export default LoginPleaseMixin;

三、性能优化

  1. 【推荐】在动画或者某些特定场景中利用 InteractionManager, 将一些耗时较长的工作安排到所有互动或动画完成之后再进行。

正例:

    componentDidMount() {
        InteractionManager.runAfterInteractions(() => {
             this.getRemoteDate();
        });
    }
  1. 【推荐】在使用 Touchable 系列组件时,进行 setState 或者大量掉帧操作,推荐使用 requestAnimationFrame。

正例:

    handlerPress = () => {
        requestAnimationFrame(() => {
            this.setState({
                visible: true
            });
        }); 
    }

四、安全规范

  1. 【强制】用户敏感数据禁止直接展示,必须对展示数据进行脱敏。
    说明:个人手机号码显示为:158****9119,隐藏中间 4 位,防止隐私泄露。
  2. 【强制】强制传入任何参数必须做有效性验证,避免过度请求服务,造成服务器压力,或者双向验证。

附录1、参考文献

[1] 阿里巴巴Java开发手册
[2] https://github.com/sunyardTime/React-Native-CodeStyle
[3] React-Native 编码规范

相关文章

网友评论

    本文标题:React Native 开发规范

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