前端JavaScript编码规范 和react编码规范
JavaScript编码规范
点击链接查看:https://github.com/ecomfe/spec/blob/master/javascript-style-guide.md
前端React编码规范
React规范
文件组织
• [强制]同一目录下不得拥有同名的.js和.jsx文件。
在使用模块导入时,倾向于不添加后缀,如果存在同名但不同后缀的文件,构建工具将无法决定哪一个是需要引入的模块。
• [强制]组件文件使用一致的.js或 .jsx后缀。
所有组件文件的后缀名从.js或.jsx中任选其一。
不应在项目中出现部分组件为.js文件,部分为.jsx的情况。
• [强制]每一个文件以export default的形式暴露一个组件。
允许一个文件中存在多个不同的组件,但仅允许通过export default暴露一个组件,其它组件均定义为内部组件。
• [强制]每个存放组件的目录使用一个index.js以命名导出的形式暴露所有组件。
同目录内的组件相互引用使用import Foo from './Foo';进行。
引用其它目录的组件使用import {Foo} from '../component';进行。
建议使用VSCode的export-index插件等插件自动生成index.js的内容。
命名规则
• [强制]组件名为PascalCase。
包括函数组件,名称均为PascalCase。
• [强制]组件名称与文件名称保持相同。
同时组件名称应当能体现出组件的功能,以便通过观察文件名即确定使用哪一个组件。
• [强制]高阶组件使用camelCase命名。
高阶组件事实上并非一个组件,而是一个“生成组件类型”的函数,因此遵守JavaScript函数命名的规范,使用camelCase命名。
• [强制]使用onXxx形式作为props中用于回调的属性名称。
使用统一的命名规则用以区分props中回调和非回调部分的属性,在JSX上可以清晰地看到一个组件向上和向下的逻辑交互。
对于不用于回调的函数类型的属性,使用动词作为属性名称。
// onClick作为回调以on开头,renderText非回调函数则使用动词
let Label = ({onClick, renderText}) => <span onClick={onClick}>{renderText()}</span>;
• [建议]使用withXxx或xxxable形式的词作为高阶组件的名称。
高阶组件是为组件添加行为和功能的函数,因此使用如上形式的词有助于对其功能进行理解。
• [建议]作为组件方法的事件处理函数以具备业务含义的词作为名称,不使用onXxx形式命名。
// Good
class Form {
@autobind
collectAndSubmitData() {
let data = {
name: this.state.name,
age: this.state.age
};
this.props.onSubmit(data);
}
@autobind
syncName() {
// ...
}
@autobind
syncAge() {
// ...
}
render() {
return (
<div>
<label>姓名:<input type="text" onChange={this.syncName} /></label>
<label>年龄:<input type="number" onChange={this.syncAge} /></label>
<button type="button" onClick={this.collectAndSubmit}>提交</button>
</div>
);
}
}
组件声明
• [强制]使用ES Class声明组件,禁止使用React.createClass。
React v15.5.0已经弃用了React.createClass函数。
// Bad
let Message = React.createClass({
render() {
return <span>{this.state.message}</span>;
}
});
// Good
class Message extends PureComponent {
render() {
return <span>{this.state.message}</span>;
}
}
• [强制]不使用state的组件声明为函数组件。
函数组件在React中有着特殊的地位,在将来也有可能得到更多的内部优化。
// Bad
class NextNumber {
render() {
return <span>{this.props.value + 1}</span>
}
}
// Good
let NextNumber = ({value}) => <span>{value + 1}</span>;
• [建议]所有组件均需声明propTypes。
propsTypes在提升组件健壮性的同时,也是一种类似组件的文档的存在,有助于代码的阅读和理解。
• [强制]对于所有非isRequired的属性,在defaultProps中声明对应的值。
声明初始值有助于对组件初始状态的理解,也可以减少propTypes对类型进行校验产生的开销。
对于初始没有值的属性,应当声明初始值为null而非undefined。
• [建议]如无必要,使用静态属性语法声明propsTypes、contextTypes、defaultProps和state。
仅当初始state需要从props计算得到的时候,才将state的声明放在构造函数中,其它情况下均使用静态属性声明进行。
• [建议]依照规定顺序编排组件中的方法和属性。按照以下顺序编排组件中的方法和属性:
a. static displayName
b. static propTypes
c. static contextTypes
d. state defaultProps
e. static state
f. 其它静态的属性
g. 用于事件处理并且以属性的方式(onClick = e => {...})声明的方法
h. 其它实例属性
i. constructor
j. getChildContext
k. componentWillMount
l. componentDidMount
m. shouldComponentUpdate
n. componentWillUpdate
o. componentDidUpdate
p. componentWillUnmount
q. 事件处理方法
r. 其它方法
s. render
• render是一个组件最容易被阅读的函数,因此放在最下方有助于快速定位。
• [建议]使用箭头函数声明函数组件。
箭头函数具备更简洁的语法(无需function关键字),且可以在仅有一个语句时省去return造成的额外缩进。
• [建议]高阶组件返回新的组件类型时,添加displayName属性。
同时在displayName上声明高阶组件的存在。
// Good
let asPureComponent = Component => {
let componentName = Component.displayName || Component.name || 'UnknownComponent';
return class extends PureComponent {
static displayName = `asPure(${componentName})`
render() {
return <Component {...this.props} />;
}
};
};
组件实现
• [建议]除顶层或路由级组件以外,所有组件均在概念上实现为纯组件(Pure Component)。
本条规则并非要求组件继承自PureComponent,“概念上的纯组件”的意思为一个组件在props和state没有变化(shallowEqual)的情况下,渲染的结果应保持一致,即shouldComponentUpdate应当返回false。
一个典型的非纯组件是使用了随机数或日期等函数:
let RandomNumber = () => <span>{Math.random()}</span>;
let Clock = () => <span>{Date.time()}</span>;
• 非纯组件具备向上的“传染性”,即一个包含非纯组件的组件也必须是非纯组件,依次沿组件树结构向上。由于非纯组件无法通过shouldComponentUpdate优化渲染性能且具备传染性,因此要避免在非顶层或路由组件中使用。
如果需要在组件树的某个节点使用随机数、日期等非纯的数据,应当由顶层组件生成这个值并通过props传递下来。对于使用Redux等应用状态管理的系统,可以在应用状态中存放相关值(如Redux使用Action Creator生成这些值并通过Action和reducer更新到store中)。
• [强制]禁止为继承自PureComponent的组件编写shouldComponentUpdate实现。
参考React的相关Issue,在React的实现中,PureComponent并不直接实现shouldComponentUpdate,而是添加一个isReactPureComponent的标记,由CompositeComponent通过识别这个标记实现相关的逻辑。因此在PureComponent上自定义shouldComponentUpdate并无法享受super.shouldComponentUpdate的逻辑复用,也会使得这个继承关系失去意义。
• [强制]为非继承自PureComponent的纯组件实现shouldComponentUpdate方法。
shouldComponentUpdate方法在React的性能中扮演着至关重要的角色,纯组件必定能通过props和state的变化来决定是否进行渲染,因此如果组件为纯组件且不继承shouldComponentUpdate,则应当有自己的shouldComponentUpdate实现来减少不必要的渲染。
• [建议]为函数组件添加PureComponent能力。
函数组件并非一定是纯组件,因此其shouldComponentUpdate的实现为return true;,这可能导致额外的无意义渲染,因此推荐使用高阶组件为其添加shouldComponentUpdate的相关逻辑。
推荐使用react-pure-stateless-component库实现这一功能。
• [建议]使用@autobind进行事件处理方法与this的绑定。由于PureComponent使用shallowEqual进行是否渲染的判断,如果在JSX中使用bind或箭头函数绑定this会造成子组件每次获取的函数都是一个新的引用,这破坏了shouldComponentUpdate的逻辑,引入了无意义的重复渲染,因此需要在render调用之前就将事件处理方法与this绑定,在每次render`调用中获取同样的引用。当前比较流行的事前绑定this的方法有2种,其一使用类属性的语法:
class Foo {
onClick = e => {
// ...
}
};
• 其二使用@autobind的装饰器:
class Foo {
@autobind
onClick(e) {
// ...
}
}
• 使用类属性语法虽然可以避免引入一个autobind的实现,但存在一定的缺陷:
a. 对于新手不容易理解函数内的this的定义。
b. 无法在函数是使用其它的装饰器(如memoize、deprecated或检验相关的逻辑等)。
• 因此,推荐使用@autobind装饰器实现this的事先绑定,推荐使用core-decorators库提供的相关装饰器实现。
JSX
• [强制]没有子节点的非DOM组件使用自闭合语法。
对于DOM节点,按照HTML编码规范相关规则进行闭合,其中void element使用自闭合语法。
// Bad
<Foo></Foo>
// Good
<Foo />
• [强制]保持起始和结束标签在同一层缩进。
对于标签前面有其它语句(如return的情况,使用括号进行换行和缩进)。
// Bad
class Message {
render() {
return <div>
<span>Hello World</span>
</div>;
}
}
// Good
class Message {
render() {
return (
<div>
<span>Hello World</span>
</div>;
);
}
}
• 对于直接return的函数组件,可以直接使用括号而省去大括号和return关键字:
let Message = () => (
<div>
<span>Hello World</span>
</div>
);
• [强制]对于多属性需要换行,从第一个属性开始,每个属性一行。
// 没有子节点
<SomeComponent
longProp={longProp}
anotherLongProp={anotherLongProp}
/>
// 有子节点
<SomeComponent
longProp={longProp}
anotherLongProp={anotherLongProp}
>
<SomeChild />
<SomeChild />
</SomeComponent>
• [强制]以字符串字面量作为值的属性使用双引号("),在其它类型表达式中的字符串使用单引号(')。
// Bad
<Foo bar='bar' />
<Foo style={{width: "20px"}} />
// Good
<Foo bar="bar" />
<Foo style={{width: '20px'}} />
• [强制]自闭合标签的/>前添加一个空格。
// Bad
<Foo bar="bar"/>
<Foo bar="bar" />
// Good
<Foo bar="bar" />
• [强制]对于值为true的属性,省去值部分。
// Bad
<Foo visible={true} />
// Good
<Foo visible />
• [强制]对于需要使用key的场合,提供一个唯一标识作为key属性的值,禁止使用可能会变化的属性(如索引)。
key属性是React在进行列表更新时的重要属性,如该属性会发生变化,渲染的性能和正确性都无法得到保证。
// Bad
{list.map((item, index) => <Foo key={index} {...item} />)}
// Good
{list.map(item => <Foo key={item.id} {...item} />)}
• [建议]避免在JSX的属性值中直接使用对象和函数表达式。
PureComponent使用shallowEqual对props和state进行比较来决定是否需要渲染,而在JSX的属性值中使用对象、函数表达式会造成每一次的对象引用不同,从而shallowEqual会返回false,导致不必要的渲染。
// Bad
class WarnButton {
alertMessage(message) {
alert(message);
}
render() {
return <button type="button" onClick={() => this.alertMessage(this.props.message)}>提示</button>
}
}
// Good
class WarnButton {
@autobind
alertMessage() {
alert(this.props.message);
}
render() {
return <button type="button" onClick={this.alertMessage}>提示</button>
}
}
• [建议]将JSX的层级控制在3层以内。
JSX提供了基于组件的便携的复用形式,因此可以通过将结构中的一部分封装为一个函数组件来很好地拆分大型复杂的结构。层次过深的结构会带来过多缩进、可读性下降等缺点。如同控制函数内代码行数和分支层级一样,对JSX的层级进行控制可以有效提升代码的可维护性。
// Bad
let List = ({items}) => (
<ul>
{
items.map(item => (
<li>
<header>
<h3>{item.title}</h3>
<span>{item.subtitle}</span>
</header>
<section>{item.content}</section>
<footer>
<span>{item.author}</span>@<time>{item.postTime}</time>
</footer>
</li>
))
}
</ul>
);
// Good
let Header = ({title, subtitle}) => (
<header>
<h3>{title}</h3>
<span>{subtitle}</span>
</header>
);
let Content = ({content}) => <section>{content}</section>;
let Footer = ({author, postTime}) => (
<footer>
<span>{author}</span>@<time>{postTime}</time>
</footer>
);
let Item = item => (
<div>
<Header {...item} />
<Content {...item} />
<Footer {...item} />
</div>
);
let List = ({items}) => (
<ul>
{items.map(Item)}
</ul>
);
前端JavaScript编码规范 和react编码规范的更多相关文章
- HTTP URL 字符转义 字符编码 、 RFC 3986编码规范
一.为什么要编码转义 通常如果一样东西需要编码,说明这样东西并不适合传输.原因多种多样,如Size过大,包含隐私数据,对于Url来说,之所以要进行编码,是因为Url中有些字符会引起歧义. 例如Url参 ...
- 前端JavaScript规范
前端JavaScript规范 http://www.imooc.com/article/1402 http://greengerong.com/blog/2015/05/09/qian-duan-ja ...
- 规范的python编码
规范的 python 编码令人赏心悦目,令代码的表达逻辑更清晰,使得工程代码更容易被维护和交流: 编码规范包括对于代码书写格式的约束,不良语法的禁用和推荐的编码手法,下面做些简要的描述: 1. 代码规 ...
- 「PSR 规范」PSR-2 编码风格规范
所有 PSR 规范请见:https://learnku.com/docs/psr https://learnku.com/laravel/t/2079/psr-specification-psr-2 ...
- Java语言编码规范 - Java语言编码规范(中文版)(http://doc.javanb.com/code-conventions-for-the-java-programming-language-zh/index.html)
目录 1 介绍 1.1 为什么要有编码规范 1.2 版权声明 2 文件名 2.1 文件后缀 2.2 常用文件名 3 文件组织 3.1 Java源文件 3.1.1 开头注释 3.1.2 包和引入语句 ...
- 前端学HTTP之实体和编码
前面的话 每天都有各种媒体对象经由HTTP传送,如图像.文本.影片以及软件程序等.HTTP要确保它的报文被正确传送,识别.提取以及适当处理.为了实现这些目标,HTTP使用了完善的标签来描述承载内容的实 ...
- JavaScript如何正确处理Unicode编码问题!
原文:JavaScript 如何正确处理 Unicode 编码问题! 作者:前端小智 Fundebug经授权转载,版权归原作者所有. JavaScript 处理 Unicode 的方式至少可以说是令人 ...
- 4.1 react 代码规范
关于 基础规范 组件结构 命名规范 jsx 书写规范 eslint-plugin-react 关于 在代码的设计上,每个团队可能都有一定的代码规范和模式,好的代码规范能够提高代码的可读性便于协作沟通, ...
- 前端规范之JS代码规范(ESLint + Prettier)
代码规范是软件开发领域经久不衰的话题,几乎所有工程师在开发过程中都会遇到或思考过这一问题.而随着前端应用的大型化和复杂化,越来越多的前端团队也开始重视代码规范.同样,前段时间,笔者所在的团队也开展了一 ...
- javascript unicode与GBK2312(中文)编码转换示例
一个javascript的unicode与GBK2312编码相互转换的方法. 代码: var GB2312UnicodeConverter = { ToUnicode: function (s ...
随机推荐
- 处理.git文件夹过大出现臃肿问题-filter-branch和BFG工具
Git开发手册 git一些不常用的命令记不住,可以查看git开发手册(https://m.php.cn/manual/view/34957.html) 1..git/objects/pack 文件过大 ...
- SketchUp Pro 2023 下载和安装教程
SketchUp Pro 2023 下载和安装教程 下载链接 123云盘:https://www.123pan.com/s/JyAKVv-NTXB.html 安装教程 演示操作系统:Windows 1 ...
- JVM篇(一) 什么是JVM,它有什么用
一.JVM的组成 1. JVM由那些部分组成,运行流程是什么? 从图中可以看出 JVM 的主要组成部分 ClassLoader(类加载器) Runtime Data Area(运行时数据区,内存分区) ...
- 【go语言】2.1.3 函数的定义和使用
在 Go 语言中,函数是一种代码抽象和复用的方式.函数可以接受参数,执行特定的操作,并返回结果. 函数的定义 函数的定义以 func 关键字开始,后面跟着函数名.参数列表.返回值列表(可选)以及函数体 ...
- 小白终于解决了在学习Go中不知道Makefile是什么的难题
如何在Go中使用Makefile 1.Makefile是什么 Makefile是一种构建工具,用于在项目中定义和执行一系列命令.它通常包含了一些规则和目标,用于编译.测试.运行和清理项目. 2.Mak ...
- centos7安装influxdb2
前言 InfluxDB是一个由InfluxData开发的开源时序型数据库,专注于海量时序数据的高性能读.高性能写.高效存储与实时分析等,广泛应用于DevOps监控.IoT监控.实时分析等场景. 服务器 ...
- 不重启Docker能添加自签SSL证书镜像仓库吗?
应用背景 在企业应用Docker规划初期配置非安全镜像仓库时,有时会遗漏一些仓库没配置,但此时应用程序已经在Docker平台上部署起来了,体量越大就越不会让人去直接重启Docker. 那么,不重启Do ...
- Vue【原创】千位符输入框(不仅只是过滤器哦)
最近和一个做金融的朋友讨论到千位符输入的问题,后来一想貌似自己项目中也会经常碰到金额数字这种输入框,要么自己做一个吧. 首先肯定要有一个正则表达式,也就是过滤器的方案里面常用的正则: 1 filter ...
- 【译】通过 GitHub Copilot Chat 简化代码优化和调试(AI 辅助编程)
今年3月,我们宣布了 Visual Studio 2022 的 GitHub Copilot Chat.通过 Chat, Copilot 已经超越了代码补全,提供了对代码工作原理的深入分析和解释.它支 ...
- 浅谈Mysql读写分离的坑以及应对的方案
一.主从架构 为什么我们要进行读写分离?个人觉得还是业务发展到一定的规模,驱动技术架构的改革,读写分离可以减轻单台服务器的压力,将读请求和写请求分流到不同的服务器,分摊单台服务的负载,提高可用性,提高 ...