[TOC]

更新说明更新时间更新人
v1.0.02021-04-15徐力

前端规范

  • 函数名使用小驼峰式命名(即首字母为小写)

    a) can: 判断是否可执行某个动作

    b) has: 判断是否含有某个值

    c) is: 判断是否为某个值

    d) get: 获取某个值

    e) set: 设置某个值

  • 常量全部为大写,使用大写字母和下划线来组合命名,下划线用以分割单词。

      const MAX_COUNT = 10;
      const URL = 'http://www.baidu.com';

JS

遵循JavaScript Standard Style规范 区别在于:我们需要分号

CSS

  • 项目工程使用less预处理语言,熟练掌握其特性。

  • 导入样式约定遵守如下:

      // Bad
      import './xxx.less'
     
      // Good
      import styles from './xxx.less'
  • 熟悉掌握使用classnames库,和redux搭配非常契合。

  • 样式名称使用小驼峰式命名(即首字母为小写)

React

  • 组件类采用es6规范的Class语法,即使再简单的类也不应该采用函数式方法创建。

  • 组件内方法顺序:

    a) constructor:做state和成员变量初始化。

    b) 静态方法:提供给外部组件调用的方法写在这里(外部可通过ref属性获取并调用)。

    c) 成员方法: 非界面交互逻辑方法,如事件监听等

    d) 生命周期方法:按照完整的生命周期顺序书写,用到哪个周期方法写哪个。

    e) sub render: 将复杂的render方法尽量分解成多个独立的sub render。

    f) render: 避免这里出现处理数据量大的运算逻辑。

    g) 成员方法: 处理组件内交互逻辑,如异步请求、界面重绘等。

  • 常量样式通过className实现,style只在某些属性是通过动态计算获取时用到

  • 路由文件夹组件文件命名用大驼峰式命名

  • React 中一个常见模式是为一个组件返回多个元素。Fragments可以让你聚合一个子元素列表,并且不在DOM中增加额外节点,不要使用<></>这样的语法糖,因为你可能会需要key属性

  • JSX中组件Props的赋值不应该存在复杂的条件判断,可读性很重要

      // Bad
      <Custom checked={(xxx && xxx)} />
     
      // Good
      const checked = (xxx && xxx);
      <Custom checked={checked} />
  • 所有组件均需声明propTypesdefaultProps

  • 避免在JSX的属性值中直接使用对象和函数表达式。

    // Bad
    class WarnButton {
      alertMessage(message) {
        alert(message);
      }
      render() {
        return <button type="button" onClick={() => this.alertMessage(this.props.message)}>提示</button>
      }
    }
     
    // Good
    class WarnButton {
      alertMessage = () => {
        alert(this.props.message);
      }
      render() {
        return <button type="button" onClick={this.alertMessage}>提示</button>
      }
    }
  • 对于需要使用key的场合,提供一个唯一标识作为key属性的值,禁止使用可能会变化的属性(如索引)。

       // Bad
      {list.map((item, index) => <Foo key={index} {...item} />)}
     
      // Good
      {list.map(item => <Foo key={item.id} {...item} />)}
  • 对于多属性需要换行,从第一个属性开始,每个属性一行。

      <SomeComponent
        longProp={longProp}
        anotherLongProp={anotherLongProp}
      >
        <SomeChild />
        <SomeChild />
      </SomeComponent>
  • 为非继承自PureComponent的纯组件实现shouldComponentUpdate方法。

  • Props名使用小驼峰命名法

      // bad
      <Foo
        UserName="hello"
        phone_number={12345678}
      />
     
      // good
      <Foo
        userName="hello"
        phoneNumber={12345678}
      />
  • 异步操作调用model内的effect方法后,不能通过传入回调的方式获取到值,这违背了Dva的编程思想.

  • 在给PureComponent组件设置Props时,避免使用常量赋值,这样会因为每次值地址不同导致组件多余的重绘

      // bad
      <Foo
        UserName="hello"
        phone_number={12345678}
      />
     
      // good
      const userName = 'hello';
      const phoneNumber = {a: 12345678};
      <Foo
        userName={userName}
        phoneNumber={phoneNumber}
      />
  • 如果组件通过ref的方法获取实例,需要知道组件更新的时候,这个函数实际上会执行两遍,因为函数的引用变了,react要清除掉老的ref,创建一个新的。清除掉老的ref时,给回调传入的参数是null,新建ref时传入的是组件或者Dom的引用,所以我们在使用ref引用时必须先判断它是否为null

    <Foo
      ref={(r) => this.input = r}
    />
     
    onInputChange = () => {
    	if (this.input) {
        	this.input.xxx
        	// do anything
        }
    }
  • 在 React 组件中,应该在 componentDidMount 中发起网络请求。这个方法会在组件第一次“挂载”(被添加到 DOM)时执行,在组件的生命周期中仅会执行一次。更重要的是,你不能保证在组件挂载之前 Ajax 请求已经完成,如果是这样,也就意味着你将尝试在一个未挂载的组件上调用 setState,这将不起作用。在 componentDidMount 中发起网络请求将保证这有一个组件可以更新了。

setState的使用注意事项

setState(updater, callback)这个方法是用来告诉react组件数据有更新,有可能需要重新渲染。它是异步的,react通常会集齐一批需要更新的组件,然后一次性更新来保证渲染的性能,所以这就给我们埋了一个坑:

那就是在使用setState改变状态之后,立刻通过this.state去拿最新的状态往往是拿不到的。

要点一

如果你需要基于最新的state做业务的话,可以在componentDidUpdate或者setState的回调函数里获取。

    // setState回调函数
    changeTitle: function (event) {
    	this.setState({ title: event.target.value }, () => this.APICallFunction());
    },
    APICallFunction: function () {
    	// Call API with the updated value
    }

要点二

设想有一个需求,需要在在onClick里累加两次,如下

	onClick = () => {
    	this.setState({ index: this.state.index + 1 });
    	this.setState({ index: this.state.index + 1 });
	}

在react眼中,这个方法最终会变成

    Object.assign(
      previousState,
      {index: state.index+ 1},
      {index: state.index+ 1},
      ...
    )

由于后面的数据会覆盖前面的更改,所以最终只加了一次.所以如果是下一个state依赖前一个state的话,推荐给setState传function

    onClick = () => {
        this.setState((prevState, props) => {
          return {quantity: prevState.quantity + 1};
        });
        this.setState((prevState, props) => {
          return {quantity: prevState.quantity + 1};
        });
    }

项目工程

提交日志

Commit message 的写法规范有多种, 我们采用Angular规范,这是目前使用最广的写法,比较合理和系统化,并且有配套的工具。

type

type 用于说明 commit 的类别,只允许使用下面的标识。
  • feat:新功能(feature)
  • fix:修补bug
  • docs:文档(documentation)
  • chore:构建过程或辅助工具的变动
  • style: 格式(不影响代码运行的变动)
  • refactor:重构(即不是新增功能,也不是修改bug的代码变动)
  • test:增加测试
  • perf: 性能优化
  • ci: 持续集成相关
  • revert: 撤销某个历史提交

scope

scope 用于说明 commit 影响的范围,比如page name、component name等等,体现本次提交修改的重点。

subject

subject 是 commit 目的的简短描述,不超过50个字符。
  • 以动词开头,使用第一人称现在时,比如change,而不是changed或changes
  • 第一个字母小写
  • 结尾不加句号(.)

分支

  • master: 只在发布时做代码合并,并在其基础上打Tag。
  • develop: 主要开发迭代分支,featurebugfix 分支在其基础迁出。
  • [feature|bugfix]-[YYYYMMDD]-v[1.0.0]: featurebugfix 分支的命名格式,版本号对应当前开发版本。

Mock

开发流程规范化:后端提供 Swagger 形式的接口文档 前端实现对应的 Mock 数据,达到前后端分离,并对项目进度的时间评估提供依据。

命名约定 

mock文件统一放在根目录的mocks文件夹下
  • 文件名: 与后端的路由层级保持一致,如后端的 /user/login/user/logout 等对用户的一系列操作,我们就可以命名为user.{js|ts}

其他

  • 不要用eslint-disable来规避eslint检查,对规范有争议的话可以讨论解决

  • 通过classnames库实现动态className的方法

    /* components/submit-button.js */
    import { Component } from 'react';
    import classNames from 'classnames/bind';
    import styles from './submit-button.css';
 
    let cx = classNames.bind(styles);
 
    export default class SubmitButton extends Component {
      render () {
        let text = this.props.store.submissionInProgress ? 'Processing...' : 'Submit';
        let className = cx({
          base: true,
          inProgress: this.props.store.submissionInProgress,
          error: this.props.store.errorOccurred,
          disabled: this.props.form.valid,
        });
        return <button className={className}>{text}</button>;
      }
    };

IDE及插件

  • 推荐使用VSCode

  • 必须安装的插件列表: editorConfigeslintstylelintprettierDebugger for Chrome