# React 推荐写法

# 基本规范

  • 每个文件只包含的一个 React 组件:
    • 联系紧密的组件可以使用「命名空间」的形式;
    • 每个文件中可包含多个纯函数组件。
  • 始终使用 JSX 语法,不要使用React.createElement创建 ReactElement,以提高编写速度、可读性、可维护性(没有 JSX 转换的特殊场景例外,如在console中测试组件)。

# 文件规范

  • 组件文件使用一致的.js.jsx后缀。所有组件文件的后缀名从.js.jsx中任选其一。不应在项目中出现部分组件为.js文件,部分为.jsx的情况。
  • 每个存放组件的目录使用一个index.js/index.jsx以命名导出的形式暴露所有组件。同目录内的组件相互引用使用import Foo from './Foo';进行。引用其它目录的组件使用import {Foo} from '../component';进行。

# 命名规范

  • 文件名:使用大驼峰命名法(PascalCase),如 MyComponent.jsx;
  • 组件命名:组件名称和文件名一致,如 MyComponent.jsx 里的组件名应该是 MyComponent;一个目录的根组件使用 index.jsx 命名,以目录名称作为组件名称;
  • 引用命名:React 组件使用大驼峰命名法(PascalCase);
  • 高阶组件使用 camelCase 命名。高阶组件事实上并非一个组件,而是一个“生成组件类型”的函数,因此遵守 JavaScript 函数命名的规范,使用 camelCase 命名。
  • 使用onXxx形式作为props中用于回调的属性名称。使用统一的命名规则用以区分props中回调和非回调部分的属性,在 JSX 上可以清晰地看到一个组件向上和向下的逻辑交互。
  • 使用 withXxx 或 xxxable 形式的词作为高阶组件的名称。高阶组件是为组件添加行为和功能的函数,因此使用如上形式的词有助于对其功能进行理解。

# 带命名空间的组件

  • 如果一个组件有许多关联子组件,可以以该组件作为命名空间编写、调用子组件。
class Form extends React.Component {
  // ...
}
class Row extends React.Component {}
class Label extends React.Component {}
class Input extends React.Component {}
Form.Row = Row;
Form.Label = Label;
Form.Input = Input;
export default Form;
// refence Form component
import Form from "./Form";
const App = (
  <Form>
    <Form.Row>
      <Form.Label />
      <Form.Input />
    </Form.Row>
  </Form>
);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 属性

# 属性设置

  • 在组件行内设置属性(以便 propTypes 校验),不要在外部改变属性的值;
  • 属性较多使用{…this.props}语法;
// good
const props = {};
props.foo = x;
props.bar = y;
const component = <Component {...props} />;
1
2
3
4
5
  • 属性值明确为true时,省略值。

# 属性对齐方式

  • 属性较少时可以行内排列;
  • 属性较多时每行一个属性,闭合标签单独成行。
// bad - too long
<input type="text" value={this.state.newDinosaurName} onChange={this.inputHandler.bind(this, 'newDinosaurName')} />
// bad - aligning attributes after the tag
<input type="text"
       value={this.state.newDinosaurName}
       onChange={this.inputHandler.bind(this, 'newDinosaurName')} />
// good
<input
  type="text"
  value={this.state.newDinosaurName}
  onChange={this.inputHandler.bind(this, 'newDinosaurName')}
 />
1
2
3
4
5
6
7
8
9
10
11
12

# 属性空格

  • 属性=前后不要添加空格
  • JSX 中的花括号前后不要添加空格。
// bad
<Foo bar={ baz } foo = "bar" />
// good
<Foo bar={baz} foo="bar" />
// good { left: '20px' } 为一个对象
<Foo style={{ left: '20px' }} />
1
2
3
4
5
6

# propTypes及默认值

  • 组件属性都应该在propTypes中声明类型;
  • 始终明确指定非必选属性的默认值。
// bad
function SFC({ foo, bar, children }) {
  return (
    <div>
      {foo}
      {bar}
      {children}
    </div>
  );
}

// good
function SFC({ foo, bar, children }) {
  return (
    <div>
      {foo}
      {bar}
      {children}
    </div>
  );
}
SFC.propTypes = {
  foo: PropTypes.number.isRequired,
  bar: PropTypes.string,
  children: PropTypes.node,
};
SFC.defaultProps = {
  bar: "",
  children: null,
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

# 引号

  • JSX 属性使用双引号"
  • JS 使用单引号'

# ()使用

  • 多行的 JSX 使用 () 包裹,有组件嵌套时使用多行模式;
// bad
return (
  <div>
    <ComponentOne />
    <ComponentTwo />
  </div>
);
// good
var multilineJsx = (
  <header>
    <Logo />
    <Nav />
  </header>
);
// good
return (
  <div>
    <ComponentOne />
    <ComponentTwo />
  </div>
);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
  • 单行 JSX 省略 ()

# 自闭合标签

  • 自闭合所有没有子组件的标签;
  • 自闭合标签/前留一个空格。
// bad
<Logo></Logo>
// very bad
<Foo                 />
// bad
<Foo
 />
// good
<Logo />
1
2
3
4
5
6
7
8
9

# 方法

  • 事件函数用public class fields
// good
class Foo extends React.Component {
  handleClick = () => {
    this.setState({ xxx: aaa });
  };
  render() {
    return <button onClick={this.handleClick}>Click me</button>;
  }
}
// bad
class Foo extends React.Component {
  handleClick() {
    this.setState({ xxx: aaa });
  }
  render() {
    return <button onClick={this.handleClick.bind(this)}>Click me</button>;
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  • 事件处理方法以 handle 开头,如 handleClick() {},用 on 的作为回调做区分

# 组件代码组织

  • 按照生命周期顺序组织组件的属性、方法;
  • 方法(属性)之间空一行;
  • render()方法始终放在最后;
  • 自定义方法 React API 方法之后、render()之前;
  • class extends React.Component顺序:
    • static属性
    • static方法
    • constructor
    • getChildContext
    • componentWillMount
    • componentDidMount
    • componentWillReceiveProps
    • shouldComponentUpdate
    • componentWillUpdate
    • componentDidUpdate
    • componentWillUnmount
    • 点击处理函数或者其他事件处理函数,如onClickSubmit()onChangeDescription()
    • render的 getter 方法,如getSelectReason()getFooterContent()
    • 可选的 render 方法,如renderNavigation()renderProfilePicture()
    • render
  • 定义 propTypes, defaultProps, contextTypes

# 六、团队其它规范

  • 6.1、尽量不手动操作 DOM
因为团队现在使用 vue 框架,所以在项目开发中尽量使用 vue 的特性去满足我们的需求,尽量(不到万不得已)不要手动操作 DOM,包括:增删改 dom 元素、以及更改样式、添加事件等。
1
  • 6.2、删除弃用代码
很多时候有些代码已经没有用了,但是没有及时去删除,这样导致代码里面包括很多注释的代码块,好的习惯是提交代码前记得删除已经确认弃用的代码,例如:一些调试的 console 语句、无用的弃用代码。
1
  • 6.3、保持必要的注释
代码注释不是越多越好,保持必要的业务逻辑注释,至于函数的用途、代码逻辑等,要通过语义化的命令、简单明了的代码逻辑,来让阅读代码的人快速看懂。
1

TIP

React + TypeScript最佳实践 ⭐️ https://juejin.cn/post/6952696734078369828/ (opens new window)