react hook 和 class 组件 在搜索列表中的写法对比

366 阅读2分钟

搜索列表的需求:根据URL里面的变化,实时刷新列表

class 组件的写法

class List extends PureComponent {
  constructor(props) {
    super(props)
    const {
      location: { query }
    } = props
    this.state = {
      filter: {
        ...query
      }
    }
  }

  componentDidUpdate() {
    const {
      location: { query }
    } = this.props
    if (this._isFilterSame(this.state.filter, query)) {
      return
    }
    this.setState(
      {
        filter: {
          ...query
        }
      },
      () => {
        this.getList()
      }
    )
  }

  _isFilterSame = (previous, current) => {
    if (previous.pageNumber !== current.pageNumber) {
      return false
    }
    if (previous.pageSize !== current.pageSize) {
      return false
    }
    if (previous.searchText !== current.searchText) {
      return false
    }
    return true
  }
  getList = () => {
    const {
      dispatch,
      location: { query }
    } = this.props
    const { pageNumber = 1, pageSize = 10, searchText } = query
    const data = {
      pageNumber,
      pageSize
    }
    if (searchText) {
      data.searchText = searchText
    }
    dispatch({
      type: 'enterpriseModel/getEnterpriseList',
      payload: data
    })
  }

  getColumns = () => {
    return [
      {
        title: '企业名称',
        align: 'left',
        dataIndex: 'name'
      },
      {
        title: '企业英文名称',
        align: 'center',
        dataIndex: 'nameEn'
      },
      {
        title: '企业简称',
        align: 'left',
        dataIndex: 'shortName'
      },
      {
        title: '域名',
        align: 'center',
        dataIndex: 'domain'
      }
    ]
  }

  _changePageIndex = pageNumber => {
    const {
      location: { query }
    } = this.props
    this.delPath(query)
    query.pageNumber = pageNumber
    this.pushRouter(query)
  }

  _onShowSizeChange = (pageNumber, pageSize) => {
    const {
      location: { query }
    } = this.props
    query.pageNumber = `${pageNumber}`
    query.pageSize = `${pageSize}`
    this.pushRouter(query)
  }

  delPath = query => {
    if (!query.countPerPage) {
      query.pageNumber = 1
    }
    if (!query.countPerPage) {
      query.pageSize = 10
    }
  }

  pushRouter = query => {
    const url = `/enterprise?${qs.stringify(query)}`
    router.push(url)
  }

  basicTableProps = () => {
    const {
      enterpriseList,
      total,
      location: {
        query: { pageSize, pageNumber }
      }
    } = this.props
    return {
      rowKey: 'id',
      dataSource: enterpriseList || [],
      columns: this.getColumns(),
      className: styles.table,
      pagination: {
        showQuickJumper: false,
        showSizeChanger: true,
        pageSizeOptions: ['10', '20', '50', '100', '200'],
        onChange: this._changePageIndex,
        onShowSizeChange: this._onShowSizeChange,
        total: total || null,
        pageSize: parseInt(pageSize, 10),
        current: parseInt(pageNumber, 10),
        showTotal: () => {
          return `${total}条记录`
        }
      }
    }
  }

  content = () => {
    return (
      <div className={styles.tableDiv}>
        <Table {...this.basicTableProps}></Table>
      </div>
    )
  }

  header = () => {
    const { searchText } = this.state
    return (
      <div className={styles.header}>
        <Search
          className={styles.search}
          placeholder={'请输入企业名称/域名'}
          onChange={this.handleChange}
          onSearch={this.handleSearch}
          value={searchText}
        ></Search>
      </div>
    )
  }

  render() {
    const { loading } = this.props
    return (
      <Spin spinning={loading.effects['enterpriseModel/getEnterpriseList']}>
        {this.header()}
        {this.content()}
      </Spin>
    )
  }
}

hook的写法

function List(props) {
  const {
    dispatch,
    loading,
    enterpriseList,
    total,
    location: { query }
  } = props

  const { pageNumber = 1, pageSize = 10, searchText: initText } = query

  const getList = useCallback(
    query => {
      const { pageNumber = 1, pageSize = 10, searchText } = query
      const data = {
        pageNumber,
        pageSize
      }
      if (searchText) {
        data.searchText = searchText
      }
      dispatch({
        type: 'enterpriseModel/getEnterpriseList',
        payload: data
      })
    },
    [dispatch]
  )

  useEffect(() => {
    getList(query)
  }, [getList, query])

  const [searchText, changeValue] = useState(initText)

  const getColumns = () => {
    return [
      {
        title: '企业名称',
        align: 'left',
        dataIndex: 'name'
      },
      {
        title: '企业英文名称',
        align: 'center',
        dataIndex: 'nameEn'
      },
      {
        title: '企业简称',
        align: 'left',
        dataIndex: 'shortName'
      },
      {
        title: '域名',
        align: 'center',
        dataIndex: 'domain'
      }
    ]
  }

  const _changePageIndex = pageNumber => {
    delPath(query)
    query.pageNumber = pageNumber
    pushRouter()
  }

  const _onShowSizeChange = (pageNumber, pageSize) => {
    query.pageNumber = `${pageNumber}`
    query.pageSize = `${pageSize}`
    pushRouter()
  }

  const pushRouter = () => {
    const url = `/enterprise?${qs.stringify(query)}`
    router.push(url)
  }

  const basicTableProps = {
    rowKey: 'id',
    dataSource: enterpriseList || [],
    columns: getColumns(),
    className: styles.table,
    pagination: {
      showQuickJumper: false,
      showSizeChanger: true,
      pageSizeOptions: ['10', '20', '50', '100', '200'],
      onChange: _changePageIndex,
      onShowSizeChange: _onShowSizeChange,
      total: total || null,
      pageSize: parseInt(pageSize, 10),
      current: parseInt(pageNumber, 10),
      showTotal: () => {
        return `${total}条记录`
      }
    }
  }

  const handleChange = e => {
    const { value } = e.target
    changeValue(value)
  }

  const handleSearch = value => {
    delPath(query)
    query.searchText = value
    if (!value) {
      delete query.searchText
    }
    pushRouter()
  }

  const delPath = query => {
    if (!query.countPerPage) {
      query.pageNumber = 1
    }
    if (!query.countPerPage) {
      query.pageSize = 10
    }
  }

  const content = useMemo(() => {
    return (
      <div className={styles.tableDiv}>
        <Table {...basicTableProps}></Table>
      </div>
    )
  }, [basicTableProps])

  const header = () => {
    return (
      <div className={styles.header}>
        <Search
          className={styles.search}
          placeholder={'请输入企业名称/域名'}
          onChange={handleChange}
          onSearch={handleSearch}
          value={searchText}
        ></Search>
      </div>
    )
  }

  return (
    <Spin spinning={loading.effects['enterpriseModel/getEnterpriseList']}>
      {header()}
      {content}
    </Spin>
  )
}

最后

其实对比下来,hook的代码量少一些,而且简单明了, 在class组件里面我要通过_isFilterSame函数来判断,URL里面的参数有没有变化, 而在hook里面我只需要把query参数传到useEffect里面,hook 自动做到了监听,省去了很多判断