代码规范
代码review中出现的问题 记录在这里
01. 代码风格-命名
-
函数命名
能够表明这个函数的用处。
class Company extends React.Component {
// bad
handleSave() {}
// good,可以带上模块名称
handleSaveCompany(){}
}
- 变量命名
能够表明这个变量的用处。
class Bank extends React.Component {
state = {
// bad
visible: false,
// good
modalVisible: false,
};
}
- model命名
// bad
export default {
effects: {
// bad
*fetch({ payload }, { call, put }) {},
// good
*fetchBank({ payload }, { call, put }) {}
}
}
- 组件属性命名
组件属性如果是函数,使用on前缀
class Bank extends React.Component {
render() {
return (
<React.Fragment>
// bad
<TableList
search={this.handleSearchCalendar}
/>
// good
<TableList
onSearch={this.handleSearchCalendar}
/>
</React.Fragment>
);
}
}
02. 代码风格-注释
// bad
/**
* 批量生成数据屏蔽规则
* @param {Array} params - 生成数据屏蔽规则列表
*/
export async function createDataRules(params) {
return request(`${HZERO_IAM}/v1/doc-types/generate-shield-rule`, {
method: 'POST',
body: params,
});
}
// good
/**
* 查询值集
* @async
* @function queryCode
* @param {object} params - 查询条件
* @param {!string} params.lovCode - 查询条件
* @returns {object} fetch Promise
*/
export async function queryCode(params = {}) {
return request(`${HZERO_PLATFORM}/v1/lovs/value`, {
query: params,
});
}
03. 表格列宽度
- 表格宽度必须有一列不存在宽度(为了在宽屏不会撑开)
- 固定列(fixed)必须有宽度
import { tableScrollWidth } from 'utils/utils';
class DataTable extends React.Component {
getColumns() {
// columns1 宽度全部给定了, 在宽度大于 300 的屏幕上, 每一列会按照一定比例放大
// bad
const columns1 = [
{
title: '银行代码',
width: 150,
dataIndex: 'bankCode',
},
{
title: '银行名称',
width: 150,
dataIndex: 'bankName',
},
];
// columns2 银行名称宽度未固定, 在任何屏幕上, 银行代码宽度会占150, 银行名称 占剩余全部宽度
// good
const columns = [
{
title: '银行代码',
width: 150,
dataIndex: 'bankCode',
},
{
title: '银行名称',
dataIndex: 'bankName',
},
];
}
render() {
const columns = this.getColumns();
return (
<Table
columns={columns}
scroll={{x: tableScrollWidth(columns)}}
/>
);
}
}
04. 代码规范-表格宽度不固定
// bad
<Table
style={{ width: 800}}
bordered
rowKey="uomId"
loading={loading}
columns={columns}
dataSource={dataSource}
pagination={paginations}
onChange={this.handleTableChane}
/>
// good
<Table
bordered
rowKey="uomId"
loading={loading}
columns={columns}
dataSource={dataSource}
pagination={paginations}
onChange={this.handleTableChane}
/>
05. 代码规范-消息提醒
// bad
notification.success({message: '保存成功'});
// good
notification.success();
06. 代码规范-引用路径
// bad
import { getResponse } from '../../../utils/utils'
// good
import { getResponse } from 'utils/utils'
07. 代码规范-表单效验国际化
// 必输效验
// bad
rules: [
{
required: true,
message: '二级域名不能为空',
},
]
// good
rules: [
{
required: true,
message: intl.get('hzero.common.validation.notNull', {
name: intl.get('hptl.portalAssign.model.portalAssign.webUrl').d('二级页面域名'),
}),
},
]
// 长度效验
// bad
rules: [
{
max: 20,
message: '长度不能超过20个字符'
},
]
// good
rules: [
{
max: 20,
message: intl.get('hzero.common.validation.max', {
max: 20,
}),
},
]
08. 代码风格-依赖引入
排序依据
第三方库
>本地绝对路径
>本地相对路径
组件
>方法
>资源
>样式
默认引入
>模块引入
- 第三方库: 通过npm安装的库(排除项目依赖-hzero等)
- 本地绝对路径:
components/Page
,utils/utils
等 通过 babel 或 webpack 的别名引入 - 本地相对路径:
../index.less
- 组件: React 组件
- 方法: 一些函数
- 资源: 图片等资源
- 样式: less 样式
- 默认引入:
import intl from 'utils/intl';
- 模块引入:
import { getResponse } from 'utils/utils';
// bad
import { Header, Content } from 'components/Page';
import { connect } from 'dva';
// good
import { connect } from 'dva';
import { Header, Content } from 'components/Page';
09. 代码风格-对象的简洁写法
// bad
const listPropsReceive = {
dataSource: receiveList,
editLine: this.editLine,
pagination,
};
// good
const listPropsReceive = {
loading,
pagination,
dataSource: receiveList,
editLine: this.editLine,
};
10. 代码风格-代码复用
// bad
<FormItem
labelCol={{ span: 10 }}
wrapperCol={{ span: 14 }}
>
</FormItem>
// good
const formLayout = {
labelCol: { span: 10 },
wrapperCol: { span: 14 },
}
<FormItem
{...formLayout}
>
// ...
</FormItem>
11. 代码规范-表单中的编码字段
新增、编辑或者充当查询条件的编码字段,需要添加 typeCase
属性
<React.Fragment>
// bad
<FormItem
label="条款代码"
>
{form.getFieldDecorator('termCode', {
initialValue: termCode,
})(
<Input
trim
inputChinese={false}
/>
)}
</FormItem>
// good
<FormItem
label="条款代码"
>
{form.getFieldDecorator('termCode', {
initialValue: termCode,
})(
<Input
trim
typeCase="upper"
inputChinese={false}
/>
)}
</FormItem>
</React.Fragment>
01. 功能优化-model 与 service 分离
// bad
export const service = {
async queryBanks(params = {}) {
const {
page = { current: 1, pageSize: 10 },
sort = { name: 'bankCode', order: 'asc' },
body,
} = params;
return request(
`${SERVICE_URL}?page=${page.current - 1}&size=${page.pageSize}&sort=${sort.name},${
sort.order
}&${stringify(body)}`
);
},
};
export const model = {
effects: {
*fetch({ payload }, { call, put }) {
const response = yield call(service.queryBanks, payload);
const list = getResponse(response);
if (list) {
yield put({
type: 'updateState',
payload: {
list,
},
});
}
},
},
};
// good
// model
import { createNodeGroup } from '../services/nodeGroupService';
export const model2 = {
effects: {
*createNodeGroup({ payload }, { call }) {
const res = yield call(createNodeGroup, payload);
return getResponse(res);
},
}
};
// service
export async function createNodeGroup(params) {
return request(`${HZERO_HSGP}/v1/${params.envId}/node-groups`, {
method: 'POST',
body: params,
});
}
02. 功能优化-Row 组件的下级须为 Col
<React.Fragment>
// bad
<Row>
<span>
{intl.get('hzero.hpfm.config.view.label.tenant').d('选择租户')}:
</span>
<Lov
style={{
width: 300,
}}
code="HPFM.TENANT"
value={selectedTenant.tenantId || 0}
onChange={this.handleTenantChange}
/>
</Row>
// good
<Row>
<Col>
<span>
{intl.get('hzero.hpfm.config.view.label.tenant').d('选择租户')}:
</span>
<Lov
style={{
width: 300,
}}
code="HPFM.TENANT"
value={selectedTenant.tenantId || 0}
onChange={this.handleTenantChange}
/>
</Col>
</Row>
</React.Fragment>
03. 功能优化-操作按钮添加loading效果
- 操作按钮: 产生副作用的按钮, 保存数据/修改数据
// bad
<Button onClick={this.handleSaveCompany}>保存</Button>
// good
<Button onClick={this.handleSaveCompany} loading={saveCompanyLoading}>保存</Button>
04. 功能优化-使用getResponse处理请求
// bad
dispatch({
type: 'concPermission/deleteHeader',
}).then(res => {
if (res && res.failed) {
// ...
}
});
// good
// dispatch
dispatch({
type: 'concPermission/deleteHeader',
}).then(res => {
if (res) {
// 调用成功
// ...
}
});
// model
export const model = {
effects: {
*deleteHeader({ interfaceServerId }, { call }) {
const res = yield call(deleteHeader, interfaceServerId);
return getResponse(res);
},
}
};
05. 功能优化-使用原生Modal
class Bank extends React.Component {
// bad
showAttrsDrawer = record => {
open({
title: intl.get(`${promptCode}.model.definition.attrs`).d('组件属性'),
side: 'right',
footer: null,
width: 800,
onOk: () => {},
children: <AttrsDrawer record={record} />,
});
};
// good
render() {
return (
<Modal
destroyOnClose
visible={modalVisible}
width="1000px"
>
...
</Modal>
);
}
}
06. 功能优化-函数参数传递
class Bank extends React.Component {
// bad
componentDidMount() {
this.handleSearch({});
}
handleSearch(fields = {}) {
// ...
}
// good
componentDidMount() {
this.handleSearch();
}
handleSearch(fields = {}) {
// ...
}
}
07. 功能优化-公共的 render 函数使用
class Bank extends React.Component {
getColumns() {
return [
// bad
{
title: '状态',
dataIndex: 'enabledFlag',
render: val => { return ( <span>{enableRender(val)}</span> ) },
},
// good
{
title: '状态',
dataIndex: 'enabledFlag',
render: enableRender,
},
];
}
}
08. 功能优化-编辑的模态框,需要单独调用详情接口,添加loading效果 - 优先级低
// 包裹 Spin
<Spin spinning={loading}>
...
</Spin>
9. 功能优化-代码规范在父组件中引入prompt后,非子路由的子组件中无需引入
10 功能优化-函数声明
class Company extends React.Component {
// bad
handleSaveCompany = () => {}
// good
@Bind()
handleSaveCompany() {}
// 或者
constructor(props) {
super(props);
this.handleSaveCompany = this.handleSaveCompany.bind(this);
}
// 声明
handleSaveCompany() {}
}
01. 性能优化-无用的父级标签,使用React.Fragment代替
class Bank extends React.Component {
// bad
render() {
return (
<div>
<div className={style['sql-execute-left']}>
<TreeTable />
</div>
<div className={style['sql-execute-right']}>
<ExecutePage />
</div>
</div>
);
}
// good
render() {
return (
<React.Fragment>
<div className={style['sql-execute-left']}>
<TreeTable />
</div>
<div className={style['sql-execute-right']}>
<ExecutePage />
</div>
</React.Fragment>
);
}
}
02. 性能优化-loading使用方式
// bad
@connect(({ sqlExecute, loading }) => ({
sqlExecute,
loading,
}))
// good
@connect(({ sqlExecute, loading }) => ({
sqlExecute,
executeSelectedLoading: loading.effects['sqlExecute/fetchExecuteResult'],
}))