ReactJS 书写建议

在之前使用 AngularJS 开发项目半年左右时间的时候,整理过一篇 《AngularJS 常用模块书写建议》,那时候团队没有太注重规范,这篇类似规范的东西使得我后来参与的项目代码质量高了不少,也帮助了我们团队其他的同学。现在在一个比较正规的团队里,平时的前端开发以 React 为主,书写规范早已通过 lint 工具 加在 pre-commit hook 里强制解决。然而还是觉得有必要写一篇书写建议,这样或许能加深理解,而不是单单地改掉 lint 后的 errorwarning

本文将以从上到下,从外到内的方式介绍如何规范地写一个 React 组件。

创建组件

Class 写法

如果组件有内部状态、方法或者 refs,使用 Class 写法:

1
2
3
4
5
6
class MyComp extends React.Component {
// ...
render() {
return <div>{this.state.hello}</div>;
}
}

这种情况下 PropTypes/DefaultProps 使用 ES7 类静态属性提案的写法:

1
2
3
4
5
6
7
8
9
10
11
class MyComp extends React.Component {
static propTypes = {
size: React.PropTypes.oneOf(['large', 'small']),
disabled: React.PropTypes.bool
};
static defaultProps = {
size: 'large',
disabled: false
};
// ...
}

Function 写法

如果没有内部状态、方法或引用 refs,使用 Function 写法:

1
2
3
function MyComp ({ hello }) {
return <div>{hello}</div>;
}

这种情况下 PropTypes/DefaultProps 使用 静态属性 的写法:

1
2
3
4
5
6
7
MyComp.propTypes = {
name: React.PropTypes.string
};

MyComp.defaultProps = {
name: 'jason'
};

组件内部书写顺序

  1. 静态方法和属性(static
  2. 生命周期方法(constructorgetChildContextcomponentWillMountcomponentDidMountcomponentWillReceivePropsshouldComponentUpdatecomponentWillUpdatecomponentDidUpdatecomponentWillUnmount
  3. 点击回调或者事件处理器(onClickSubmitonChangeDescription
  4. 可选的 render 方法(renderNavigationrenderProfilePicture
  5. render 方法(必须有返回值)

方法的写法

推荐两种写法,一是箭头函数:

1
2
3
4
5
6
7
8
9
class MyComp extends Component {
handleClick = () => {
console.log(this);
}

render() {
return <div onClick={this.handleClick}>Please Click!</div>;
}
}

二是在构造函数中绑定:

1
2
3
4
5
6
7
8
9
10
11
12
13
class Some extends Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick = () => {
console.log(this);
}

render() {
return <div onClick={this.handleClick}>Please Click!</div>;
}
}

State

对于简单的初始化,直接使用 ES7 实例属性提案声明写法:

1
2
3
4
5
6
class MyComp extends React.Component {
state = {
foo: 'bar'
};
// ....
}

对于需要计算后才能初始化的 State,使用构造函数声明写法:

1
2
3
4
5
6
7
8
9
class MyComp extends React.Component {
constructor(props) {
super(props);
this.state = {
foo: 'bar'
};
}
// ....
}

不要对 this.state 赋值,使用 this.setState() 更新 State:

1
2
3
4
5
6
7
8
// bad
this.state.foo = 'bar';
this.forceUpdate();

// good
this.setState({
foo: 'bar'
})

Props

属性名采用 camelCase 风格:

1
2
3
4
<Foo
userName="hello"
phoneNumber={12345678}
/>

如果属性为 true,可以直接省略:

1
2
3
4
5
// bad
<Foo hidden={true} />

// good
<Foo hidden />

数组中或者遍历中输出相同的 React 组件,属性 key 必需,且不要使用 index 作为 key,推荐使用唯一ID。

1
2
3
4
5
6
{todos.map(todo => (
<Todo
{...todo}
key={todo.id}
/>
))}

其他

命名

React 组件的扩展名使用 .jsx

文件名使用 PascalCase 命名(如 MyComp.jsx),组件名使用和文件名相同的名字。如果组件是一个文件夹,那么使用 index.js 作为入口文件。

标签

对于没有子元素的标签自关闭,对于有多个属性的使用多行书写,并在新行关闭:

1
2
3
4
5
6
<Foo className="stuff" />

<Foo
bar="bar"
baz="baz"
/>

引号

属性值使用双引号,其他都使用单引号。

1
2
<Foo bar="bar" />
<Foo style={{ left: '20px' }} />

空格

总是在自闭合的标签/>前加一个空格。不要在JSX 的 {} 引用括号里两边加空格:

1
2
3
<Foo />

<Foo bar={baz} />

括号

将多行的 JSX 标签写在 () 里,单行可以省略。

1
2
3
4
5
6
7
render() {
return (
<MyComp className="long body" foo="bar">
<MyChild />
</MyComp>
);
}

参考

Airbnb React/JSX Style Guide

坚持原创技术分享,您的支持将鼓励我继续创作!