推荐使用 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中。
在组件开发过程中只将修改后需要重新渲染界面的属性定义到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 模块是编译时输出接口。
-
