Skip to content

Latest commit

 

History

History
328 lines (241 loc) · 10.1 KB

develop-react.md

File metadata and controls

328 lines (241 loc) · 10.1 KB

React 开发规范

IDE

推荐使用 VSCode 1.32.3 以上版本(含 1.32.3)

代码格式规范

  • 代码格式化与校验

代码格式化与校验采用:ESLint + prettier。在 VSCode 中做相应的设置:

  • 声明规范

    • 函数声明

    推荐采用箭头函数写法,箭头函数写法的优点是自动绑定this对象

    class HelloWorld extends Component {
      // 采用箭头函数方式声明函数
      helloWorldClickHandle = () => {};
    
      render() {
        return <div onClick={this.helloWorldClickHandle}>HelloWOrld</div>;
      }
    }
    • 属性与变量声明

    React 中的属性和变量主要有:对象内部属性,state 属性、函数内部变量和 PropTypes 属性。对象内部属性和 state 属性必须在 construction 函数中先定义。函数内部变量声明注意修饰符,变量用: let,常量用:const。PropTypes 声明如果是必输属性,必须加 isRequired修饰符。

    class HelloWorld extends Component {
      construction(props) {
        super(props);
    
        this.objAtt = ""; // 对象内部属性在此定义
        this.state = {
          stateAtt: "" // state 属性在此定义
        };
      }
      // 采用箭头函数方式声明函数
      helloWorldClickHandle = () => {
        // 函数内部变量用:let
        let a = "";
        a = a + 1;
        console.log(a);
      };
    
      render() {
        // 函数内部常量用:const
        const { stateAtt } = this.state;
        return (
          <div onClick={this.helloWorldClickHandle}>HelloWOrld {stateAtt}</div>
        );
      }
    }
    
    // 定义 PropTypes
    HelloWorld.propTypes = {
      remove: PropTypes.func.isRequired
    };
  • 命名规则

    • 类的命名规则

    类命名采用从第一个单词的首字母大写的骆驼式命名法。如果属性名过长(超过 30 个字符)可以简写,简写字符采用大写方式。

    • 函数命名规则

    函数命名采用第一个单词的首字母小写,其后单词的首字母大写的骆驼式命名法。如果属性名过长(超过 30 个字符)可以简写,简写字符采用大写方式。

    例如:helloWorldClickHandle=()=>{}

    • 属性和变量命名规则

    属性和变量命名采用第一个单词的首字母小写,其后单词的首字母大写的骆驼式命名法。如果属性名过长(超过 30 个字符)可以简写,简写字符采用大写方式。

    例如:userCode

生命周期函数使用规范

  • componentWillReceiveProps

尽量不要在componentWillReceiveProps中做setState操作,因此正常情况下props的变化将自动重新渲染界面。如果某一个功能必须在componentWillReceiveProps中操作setState,特别注意需要做缓存处理。

示例:

class HelloWorld extends Component {
  construction(props) {
    super(props);
    this.state = {
      stateAtt = "";
    };
  }
  componentWillReceiveProps=(nextProps)=>{
    const {stateAtt} = this.state;
    // 增加缓存判断
    if(nextProps && nextProps.stateAtt !== this.state.stateAtt){
      this.setState({stateAtt: nextProps.stateAtt});
    }
  }
  render() {
    return <div>HelloWOrld</div>;
  }
}
  • componentWillUpdate

禁止在componentWillUpdate中做setState操作,将会导致死循环。

  • componentWillMount

在componentWillMount中做一些初始设置,动态事件监听等,注意动态设置的地方在组件销毁的时候需要释放。

  • componentWillUnmount

在componentWillUnmount中做一些资源释放操作,例如:事件销毁(详见下文中:性能&内存中的事件监听和移除)

state 使用规范

强调:只有需要重新渲染的属性才放到state中。

在组件开发过程中只将修改后需要重新渲染界面的属性定义到this.state中(即:this.setState({att: 'newdata'})),对于不需要重新渲染界面,又需要在对象内部全局使用的属性直接定义到this对象上(即:this.att = 'newdata')。

this.att 与 this.state.att 还有个最重要的区别:this.att是同步属性,this.state.att是异步属性。所以以下写法可能拿不到最新的state值:

this.setState({ att: "newdata" });
console.log(this.state.att);

性能&内存

  • 事件监听与移除

组件内动态监听事件需要注意事件的定义和销毁。推荐采用在componentWillMount中动态监听事件,在componentWillUnmount中动态销毁事件。

示例:

class HelloWorld extends Component {
  componentWillMount() {
    // 定义事件
    document.addEventListener("mousedown", this.docClickHandle);
  }

  docClickHandle = e => {};

  componentWillUnmount() {
    // 移除事件
    document.removeEventListener("mousedown", this.docClickHandle);
  }

  render() {
    return <div>HelloWOrld</div>;
  }
}
  • key 的使用规范

React 列表渲染时,需要通过key来标识列表每一项的唯一性,从而提高操作型列表(对列表内容做增,删,改操作)页性能。

默认情况下如果未设置key,React会自动采用对应列表中的索引index做key。这种方式对于只是显示型列表来说也是没有问题的。但是对于操作型列表来说,变更操作(特别是删除与新增)对应索引会变化,将导致整个列表渲染(而不是差异化渲染)。

因此推荐使用的key是数据项中的唯一标识属性,例如:id。

特别注意:不要使用动态uuid方式,动态uuid方式解除了react中key的警告,但是每次渲染都会重新生成新的uuid,导致列表属性渲染。

示例:<li key={uuid()}> </li>

示例:

class HelloWorld extends Component {
  construction(props) {
    super(props);
    this.state = {
      data: [
        { label: "item1", id: "item-id-1" },
        { label: "item1", id: "item-id-1" }
      ]
    };
  }

  render() {
    const { data } = this.state;
    return (
      <div>
        HelloWOrld List:
        <ul>
          {data && data.map(item=>{
            return <li key={item.id}>{item.label}</l>
          })}
        </ul>
      </div>
    );
  }
}
  • 垃圾清理

使用具备垃圾收集机制的语言编写程序,开发人员一般不必操心内存管理的问题。但是, JavaScript 在进行内存管理及垃圾收集时面临的问题还是有点与众不同。其中最主要的一个问题,就是分配给 Web 浏览器的可用内存数量通常要比分配给桌面应用程序的少。这样做的目的主要是出于安全方面的考虑, 目的是防止运行 JavaScript 的网页耗尽全部系统内存而导致系统崩溃。内存限制问题不仅会影响给变量 分配内存,同时还会影响调用栈以及在一个线程中能够同时执行的语句数量。 因此,确保占用最少的内存可以让页面获得更好的性能。而优化内存占用的最佳方式,就是为执行 中的代码只保存必要的数据。一旦数据不再有用,最好通过将其值设置为 null 来释放其引用——这个 做法叫做 解除引用(dereferencing)。这一做法适用于大多数全局变量和全局对象的属性。

  • 局部变量

正常情况下,局部变量会在它们离开执行环境时自动被解除引用。特别注意:如果使用闭包,需要对闭包函数做销毁,函数内部的变量也将自动销毁。

function createPerson(name) {
  let att = ""; // 函数内部局部变量
}
  • 全局对象
function createPerson(name) {
  var localPerson = new Object();
  localPerson.name = name;
  return localPerson;
}
var globalPerson = createPerson("Nicholas");
// 手工解除 globalPerson 的引用
globalPerson = null;

组件开发规范

  • PropTypes

组件化模式开发往往需要提供外部属性props。对外的props属性要求对类型和是否必须输入做强制规范。完整示例:

class HelloWorld extends Component {
  render() {
    const { name } = this.props;
    return <div>userName: {name}</div>;
  }
}

// 定义 PropTypes
HelloWorld.propTypes = {
  name: PropTypes.string.isRequired
};

PropTypes 支持的类型如下:

// 可以声明 prop 为指定的 JS 基本类型。默认
// 情况下没有isRequired,这些 prop 都是可传可不传的。
optionalArray: React.PropTypes.array,
optionalBool: React.PropTypes.bool,
optionalFunc: React.PropTypes.func,
optionalNumber: React.PropTypes.number,
optionalObject: React.PropTypes.object,
optionalString: React.PropTypes.string,

// 所有可以被渲染的对象:数字,
// 字符串,DOM 元素或包含这些类型的数组。
optionalNode: React.PropTypes.node,

// React 元素
optionalElement: React.PropTypes.element,

// 用 JS 的 instanceof 操作符声明 prop 为类的实例。
optionalMessage: React.PropTypes.instanceOf(Message),

// 用 enum 来限制 prop 只接受指定的值。
optionalEnum: React.PropTypes.oneOf(['News', 'Photos']),

// 指定的多个对象类型中的一个
optionalUnion: React.PropTypes.oneOfType([
  React.PropTypes.string,
  React.PropTypes.number,
  React.PropTypes.instanceOf(Message)
]),

// 指定类型组成的数组
optionalArrayOf: React.PropTypes.arrayOf(React.PropTypes.number),

// 指定类型的属性构成的对象
optionalObjectOf: React.PropTypes.objectOf(React.PropTypes.number),

// 特定形状参数的对象
optionalObjectWithShape: React.PropTypes.shape({
  color: React.PropTypes.string,
  fontSize: React.PropTypes.number
}),

// 自定义验证器。如果验证失败需要返回一个 Error 对象。不要直接
// 使用 `console.warn` 或抛异常,因为这样 `oneOfType` 会失效。
customProp: function(props, propName, componentName) {
  if (!/matchme/.test(props[propName])) {
    return new Error('Validation failed!');
  }
}

模块使用规范

项目源码必须采用ES6的模块语法,即:import 命令和 export 命令。

构件环境(例如:webpack)由于构件工具不一定支持 ES6,因此可以使用CommonJS的模块语法。

  • ES6模块注意事项

    • ES6 模块输出的是值的引用。(需要特别注意)

    • ES6 模块是编译时输出接口。