您的当前位置:首页正文

React Hooks 初使用

来源:华拓网

React Hooks 使用

使用感想

  1. 更加利于阅读的代码
  2. 代码量更少
  3. 使用更方便
  4. 由原代码修改为 Hooks 代码也很方便

经验

componentDidMount 和 componentDidUpdate 的逻辑不同;
可以使用 带第二个参数的 useEffects 来表示 componentDidMount

 useEffect(() => {
    handleSearch();
  }, []);

代码对比

总体代码量对比

文件名 代码行数 使用Hooks后代码行数
index.js 330 249
DataTable.js 179 118
SearchForm.js 110 97
ActualValueEditModal.js 233 145

执行 cat dir/**.* | egrep -v '^\s*$|^.{1}$' | wc -l 去除空行 和 源代码中样式文件代码数

修改前代码行数 修改后代码行数
767 557

index.js 文件代码对比

修改前的代码

/**
 * 基础数据管理
 * BasicData
 * @date 2019-05-28
 * @copyright 2019-05-28 © HAND
 */

import React, {Component} from 'react';
import {connect} from 'dva';
import {Bind} from 'lodash-decorators';
import {Button, Popconfirm} from 'hzero-ui';
import queryString from "query-string";

import {Content, Header} from 'components/Page'

import intl from 'utils/intl';
import notification from 'utils/notification';
import formatterCollections from "utils/intl/formatterCollections";
import {openTab} from "utils/menuTab";

import {getFieldsValueByRef} from '@/utils/utils';

import SearchForm from "./SearchForm";
import DataTable from "./DataTable";
import ActualValueEditModal from "./ActualValueEditModal";

import styles from './styles.less';

const id = 'id';

@connect(
  mapStateToProps,
  mapDispatchToProps
)
@formatterCollections({code: ['hnlp.basicData']})
export default class BasicData extends Component {
  // #endregion
  constructor(props) {
    super(props);
    this.searchFormRef = React.createRef();
    this.state = {
      selectedRows: [],
      selectedRowKeys: [],
      editActualValueModalVisible: false,
      // pagination: {}, // 存储分页信息
    };
  }

  componentDidMount() {
    const {init} = this.props;
    init();
    this.handleSearch();
  }

  // #region gen functions


  reload() {
    const {pagination} = this.state;
    this.handleSearch(pagination);
  }

  // #region data inv
  handleSearch(pagination = {}) {
    const {query} = this.props;
    const queryData = getFieldsValueByRef(this.searchFormRef);
    this.setState({
      pagination,
      selectedRows: [],
      selectedRowKeys: [],
    });
    return query({
      query: {...queryData, ...pagination},
    })
  }

  // #end

  // #region Header Btn Functions

  /**
   * 批量导入
   */
  @Bind()
  handleBatchImport() {
    openTab({
      key: '/hnlp/data-import/HNLP.BASIC_DATA',
      search: queryString.stringify({
        key: '/hnlp/data-import/HNLP.BASIC_DATA',
        title: 
        action: 
      }),
    });
  }

  @Bind()
  async handleDelBtnClick() {
    const {selectedRows = []} = this.state;
    const {removeBatch} = this.props;
    removeBatch({records: selectedRows})
      .then(res => {
        if (res) {
          notification.success();
          this.reload();
        }
      })
  }

  delBtnDisabled() {
    const {selectedRows = []} = this.state;
    return selectedRows.length === 0;
  }

  // #endregion

  // #region DataTable
  @Bind()
  handleRowSelectionChange({selectedRows = [], selectedRowKeys = []}) {
    this.setState({
      selectedRowKeys,
      selectedRows,
    })
  }

  @Bind()
  handleRecordEdit(record) {
    this.setState({
      editActualValueModalVisible: true,
      editRecord: record,
    });
  }

  @Bind()
  handleTableChange(page, filter, sort) {
    this.handleSearch({page, sort});
  }

  // #endregion

  // #region EditFormModal
  @Bind()
  handleRecordActualValueEditOk(record) {
    const {update} = this.props;
    const {editRecord} = this.state;
    update({record: {...editRecord, ...record}, id: editRecord[id]}).then((res) => {
      if (res) {
        notification.success();
        this.closeEditFormModal();
        this.reload();
      }
    })
  }

  @Bind()
  handleRecordActualValueEditCancel() {
    this.closeEditFormModal();
  }

  closeEditFormModal() {
    this.setState({
      editActualValueModalVisible: false,
      editRecord: {},
    });
  }

  // #endregion

  // #region SearchForm
  @Bind()
  handleSearchFormSubmit() {
    this.handleSearch();
  }

  // #endregion

  render() {
    const {
      dataSource,
      pagination,
      removeBatchLoading,
      updateLoading,
      queryLoading,
    } = this.props;
    const {
      selectedRowKeys,
      editActualValueModalVisible = false,
      editRecord,
    } = this.state;
    const languageMessage = this.getLanguageMessage();
    return (
      <React.Fragment>
        <Header>
          <Popconfirm
            
            onConfirm={this.handleDelBtnClick}
          >
            <Button
              disabled={this.delBtnDisabled()}
              loading={removeBatchLoading}
              type="primary"
            >
              
            </Button>
          </Popconfirm>
          <Button icon="import" onClick={this.handleBatchImport}>
            
          </Button>
        </Header>
        <Content className={styles['hnlp-basic-data']}>
          <SearchForm
            languageMessage={languageMessage}
            wrappedComponentRef={this.searchFormRef}
            onSearch={this.handleSearchFormSubmit}
            queryLoading={queryLoading}
            removeBatchLoading={removeBatchLoading}
          />
          <DataTable
            onRowSelectionChange={this.handleRowSelectionChange}
            onRecordActualValueEdit={this.handleRecordEdit}
            onChange={this.handleTableChange}
            dataSource={dataSource}
            pagination={pagination}
            languageMessage={languageMessage}
            selectedRowKeys={selectedRowKeys}
            queryLoading={queryLoading}
            removeBatchLoading={removeBatchLoading}
          />
          <ActualValueEditModal
            languageMessage={languageMessage}
            visible={editActualValueModalVisible}
            record={editRecord}
            onOk={this.handleRecordActualValueEditOk}
            onCancel={this.handleRecordActualValueEditCancel}
            updateLoading={updateLoading}
          />
        </Content>
      </React.Fragment>
    );
  }
}

function mapStateToProps({nlpBasicData = {}, loading = {}}) {
  const {
    dataSource,
    pagination,
    enums,
  } = nlpBasicData;
  return {
    dataSource,
    pagination,
    enums,
    initLoading: loading.effects['nlpBasicData/init'],
    removeBatchLoading: loading.effects['nlpBasicData/removeBatch'],
    updateLoading: loading.effects['nlpBasicData/update'],
    queryLoading: loading.effects['nlpBasicData/query'],
  };
}

function mapDispatchToProps(dispatch) {
  return {
    init: (payload) => {
      return dispatch({
        type: 'nlpBasicData/init',
        payload,
      })
    },
    removeBatch: (payload) => {
      return dispatch({
        type: 'nlpBasicData/removeBatch',
        payload,
      });
    },
    update: (payload) => {
      return dispatch({
        type: 'nlpBasicData/update',
        payload,
      });
    },
    query: (payload) => {
      return dispatch({
        type: 'nlpBasicData/query',
        payload,
      });
    },
  };
}

修改后的代码, 删除一些无关代码

/**
 * BasicData
 * @date 2019-05-23
 * @copyright 2019 © HAND
 */

import React, {useEffect, useRef, useState} from 'react';
import {Popconfirm, Button} from 'hzero-ui'
import {connect} from 'dva';

import {Content, Header} from 'components/Page';

import formatterCollections from "utils/intl/formatterCollections";
import intl from 'utils/intl';
import notification from 'utils/notification';

import SearchForm from "./SearchForm";
import DataTable from "./DataTable";
import ActualValueEditModal from "./ActualValueEditModal";

/**
 * 通过表单的ref获取表单的数据
 * @param {React.ref} ref
 * @returns {{}|*}
 */
export function getFieldsValueByRef(ref) {
  if (ref.current) {
    const form = ref.current;
    return form.getFieldsValue();
  }
  return {};
}

const id = 'id';

function BasicData(props) {
  const {
    dataSource,
    pagination,
    removeBatchLoading,
    updateLoading,
    queryLoading,
  } = props;
  // #region use hook
  const [selectedRowKeys, setSelectedRowKeys] = useState([]);
  const [selectedRows, setSelectedRows] = useState([]);
  const [reloadPagination, setReloadPagination] = useState();
  const [editActualValueModalVisible, setEditActualValueModalVisible] = useState(false);
  const [editRecord, setEditRecord] = useState({});
  const searchFormRef = useRef(null);
  const handleSearch = (pagination = {}) => {
    const {query} = props;
    const queryData = getFieldsValueByRef(searchFormRef);
    setReloadPagination(pagination);
    setSelectedRowKeys([]);
    setSelectedRows([]);
    return query({
      query: {...queryData, ...pagination},
    });
  };
  useEffect(() => {
    handleSearch();
  }, []);
  // #endregion
  const delBtnClick = () => {
    const {removeBatch} = props;
    removeBatch({records: selectedRows})
      .then(res => {
        if (res) {
          notification.success();
          reload();
        }
      })
  };
  const onRowSelectionChange = ({selectedRowKeys = [], selectedRows = []}) => {
    setSelectedRowKeys(selectedRowKeys);
    setSelectedRows(selectedRows)
  };
  const onRecordEdit = (record) => {
    setEditActualValueModalVisible(true);
    setEditRecord(record);
  };
  const onTableChange = (page, filter, sort) => {
    handleSearch({page, sort});
  };
  const reload = () => {
    handleSearch(reloadPagination);
  };
  const closeEditFormModal = () => {
    setEditActualValueModalVisible(false);
    setEditRecord({});
  };
  const onRecordActualValueEditOk = (record) => {
    const {update} = props;
    update({record: {...editRecord, ...record}, id: editRecord[id]}).then((res) => {
      if (res) {
        notification.success();
        closeEditFormModal();
        reload();
      }
    })
  };
  const onRecordActualValueEditCancel = () => {
    closeEditFormModal();
  };
  const languageMessage = getLanguageMessage();
  return (
    <>
      <Header>
        <Popconfirm
          
          onConfirm={delBtnClick}
        >
          <Button
            disabled={selectedRows.length === 0}
            loading={removeBatchLoading}
            type="primary"
          >
            
          </Button>
        </Popconfirm>
      </Header>
      <Content>
        <SearchForm
          languageMessage={languageMessage}
          queryLoading={queryLoading}
          removeBatchLoading={removeBatchLoading}
          onSearch={handleSearch}
          ref={searchFormRef}
        />
        <DataTable
          onRowSelectionChange={onRowSelectionChange}
          onRecordActualValueEdit={onRecordEdit}
          onChange={onTableChange}
          dataSource={dataSource}
          pagination={pagination}
          languageMessage={languageMessage}
          selectedRowKeys={selectedRowKeys}
          queryLoading={queryLoading}
          removeBatchLoading={removeBatchLoading}
        />
        <ActualValueEditModal
          languageMessage={languageMessage}
          visible={editActualValueModalVisible}
          record={editRecord}
          onOk={onRecordActualValueEditOk}
          onCancel={onRecordActualValueEditCancel}
          updateLoading={updateLoading}
        />
      </Content>
    </>
  );
}

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(formatterCollections({code: ['hnlp.basicData']})(BasicData));


function mapStateToProps({nlpBasicData = {}, loading = {}}) {
  const {
    dataSource,
    pagination,
    enums,
  } = nlpBasicData;
  return {
    dataSource,
    pagination,
    enums,
    initLoading: loading.effects['nlpBasicData/init'],
    removeBatchLoading: loading.effects['nlpBasicData/removeBatch'],
    updateLoading: loading.effects['nlpBasicData/update'],
    queryLoading: loading.effects['nlpBasicData/query'],
  };
}

function mapDispatchToProps(dispatch) {
  return {
    init: (payload) => {
      return dispatch({
        type: 'nlpBasicData/init',
        payload,
      })
    },
    removeBatch: (payload) => {
      return dispatch({
        type: 'nlpBasicData/removeBatch',
        payload,
      });
    },
    update: (payload) => {
      return dispatch({
        type: 'nlpBasicData/update',
        payload,
      });
    },
    query: (payload) => {
      return dispatch({
        type: 'nlpBasicData/query',
        payload,
      });
    },
  };
}