• 代码规范


    代码review中出现的问题 记录在这里

    01. 代码风格-命名

    class Company extends React.Component {
        // bad 
        handleSave() {}
        
        // good,可以带上模块名称
        handleSaveCompany(){}
    }
    

    能够表明这个变量的用处。

    class Bank extends React.Component {
      state = {
        // bad
        visible: false,
        
        // good
        modalVisible: false,
      };
    }
    
    // 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. 表格列宽度

    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. 代码风格-依赖引入

    排序依据

    第三方库 > 本地绝对路径 > 本地相对路径

    组件 > 方法 > 资源 > 样式

    默认引入 > 模块引入

    // 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'],
    }))