最近上手做一个公司项目,前端用React, 所以为了减少冗余代码,对组件的复用率要求很高,这不需要一个React table component
为了实现当前的业务需求小编很快写了第一个component
分析:table分为两个部分header和body,header是固定的,而body的列数固定,但是行数不固定。对于data,也就是table的body,是一个对象数组,每一个对象就是table的一行,对象的属性名称也是固定的。根据上述分析结果,我写了下面这个component。
1.第一个table component
先上代码:
import React from 'react'
import PropTypes from 'prop-types'
import { Table } from 'react-bootstrap'
import { RowHead } from './style'
const TableHeader = props => {
const { data, headerFormatter } = props
return (
<thead>
<RowHead>
{data &&
data.map(item => <th key={item}> {headerFormatter ? headerFormatter(item) : item}</th>)}
</RowHead>
</thead>
)
}
TableHeader.propTypes = {
data: PropTypes.arrayOf(PropTypes.string).isRequired,
headerFormatter: PropTypes.func.isRequired,
}
const TableColumns = props => {
const { data, columnNames, formatter } = props
return (
<tdoby>
{data && columnNames &&
data.map(item => (
<tr key={item.id}>
{columnNames.map(key => (
<td key={item.id}>{formatter(key, item[key], item.id)}</td>
))}
</tr>
))}
</tdoby>
)
}
TableColumns.propTypes = {
data: PropTypes.arrayOf(PropTypes.object).isRequired,
columnNames: PropTypes.arrayOf(PropTypes.string).isRequired,
formatter: PropTypes.func.isRequired,
}
const TableContainer = ({ data, headers, columnNames, formatter, headerFormatter }) => (
<Table responsive>
<TableHead data={header} headerFormatter={headerFormatter} />
<TableColumns data={data} columnNames={columnNames} formatter={formatter} />
</Table>
)
TableContainer.propTypes = {
headers: PropTypes.arrayOf(PropTypes.string).isRequired,
headerFormatter: PropTypes.func.isRequired,
columnNames: PropTypes.arrayOf(PropTypes.string).isRequired,
formatter: PropTypes.func.isRequired,
data: PropTypes.arrayOf(PropTypes.object).isRequired,
}
export default TableContainer
总结:
细心的同学不难发现,首先有许多重复的代码, TableContainer.propTypes TableHeader.propTypes TableColumns.propTypes
对于header,如果这么写,header就显示同样的format,不能实现对表头每一个名称进行个性化的定制。
body同样的道理,使所有的行得每个元素都具有相同的format,或者在使用此component时,需要进行大量的判断,根据不同的字段,赋予不同的format。这种component简直有同于无。
很明显,不改进,codeReview肯定过不了。
2.第二个react table component
import React from 'react' import PropTypes from 'prop-types' import { Table } from 'react-bootstrap' import { RowHead } from './style' const HeaderCell = props => { const { header, headerFormatter } = props return <th> {headerFormatter ? headerFormatter(header) : header} </th> } const HeaderCellPropTypes = { header: PropTypes.arrayOf(PropTypes.string).isRequired, headerFormatter: PropTypes.oneOfType([PropTypes.func, PropTypes.element]).isRequired, } HeaderCell.propTypes = HeaderCellPropTypes const ColumnCell = props => { const { value, formatter, coluumnId } = props return <td> {formatter ? formatter(value, coluumnId) : value}</td> } ColumnCell.propTypes = { value: PropTypes.string.isRequired, formatter: PropTypes.oneOfType([PropTypes.func, PropTypes.element]).isRequired, coluumnId: PropTypes.string.isRequired, } const TableContainer = ({ cloumns, data }) => ( <Table responsive> <thead> <RowHead> {cloumns && cloumns.map(item => ( <HeaderCell key={item.header} header={item.header} headerFormatter={item.headerFormatter} /> ))} </RowHead> </thead> <tbody> {data && cloumns && data.map(item => ( <tr key={item.id}> {cloumns.map(cell => ( <ColumnCell key={item.id} coluumnId={item.id} formatter={item.formatter} value={item[cell.accessor]} /> ))} </tr> ))} </tbody> </Table> ) TableContainer.propTypes = { cloumns: PropTypes.arrayOf( PropTypes.shape({ ...HeaderCellPropTypes, accessor: PropTypes.oneOf(PropTypes.func, PropTypes.string), formatter: PropTypes.oneOfType([PropTypes.func, PropTypes.element]).isRequired, }) ).isRequired, data: PropTypes.arrayOf(PropTypes.object).isRequired, }
分析: 第一个Component的所有的不足,在第二个component中变成了优势。good
export default ReactTableComponent