@reactabular/table
provides three components: Table.Provider
, Table.Header
, and Table.Body
:
-
Table.Provider
attaches column and renderer definition (optional) to the table. -
Table.Header
connects to the table and renders eachheaderCell
from the column definition. -
Table.Body
connects to the table and renders eachbodyCell
from the column definition. It also accepts rows to render.
Table.Provider
Table.Provider
is the core of Reactabular. It sets up a context and maps the column
definition to its children components. The following example illustrates the basic idea.
/*
import * as Table from '@reactabular/table';
*/
const rows = [
{
id: 100,
name: 'Adam',
dad: 'John',
lovesBeeGees: true
},
{
id: 101,
name: 'Brian',
dad: 'George',
lovesBeeGees: false
},
];
const columns = [
{
headerCell: 'Name',
bodyCell: ({ name }, { renderer }) => renderer(name)
},
{
headerCell: 'Dad',
bodyCell: ({ dad }, { renderer }) => renderer(dad)
}
];
<Table.Provider columns={columns}>
<Table.Header />
<Table.Body rows={rows} rowKey="id" />
</Table.Provider>
Table.Header
Table.Header
renders a table header within a Table.Provider
context.
<Table.Provider columns={columns}>
<Table.Header />
<Table.Body rows={rows} rowKey="id"/>
<Table.Header />
</Table.Provider>
Table.Header
Customizing It is possible to customize a header by using the renderer interface. This way you can implement filtering per column for instance. Here search.Columns
injects an additional row for the filter controls:
// XXXXX: Fix search.Columns - needs property field
const renderers = {
header: {
wrapper: (children, { renderer }) => renderer(
<React.Fragment>
{children}
<search.Columns
query={{}}
columns={columns}
onChange={value => console.log('new value', value)}
/>
</React.Fragment>
)
}
};
<Table.Provider columns={columns} renderers={renderers}>
<Table.Header />
<Table.Body rows={rows} rowKey="id" />
</Table.Provider>
Table.Body
Table.Body
renders table rows
within a Table.Provider
context. It accepts either an array of objects or an array of arrays (see the Excel example). In the former case you should define a rowKey
. This allows React to render in a more performant way.
Most often you'll define rowKey
as a string. An alternative is to define it using a function like this: rowKey={({ rowData, rowIndex }) => rowData.nested.id}
. This is useful if your key is nested or related to some other data. Another way to avoid this problem is to generate the field using reactabular-resolve
and then point to that through a string.
Example:
<Table.Provider
className="pure-table pure-table-striped"
columns={columns}
>
<Table.Header />
<Table.Body rows={rows.filter(r => r.name === 'Adam')} rowKey="id" />
<Table.Header />
<Table.Body rows={rows.filter(r => r.name === 'Brian')} rowKey="id" />
</Table.Provider>
Getting Refs
Sometimes you might need to access the underlying DOM nodes for measuring etc. This can be achieved as follows:
// XXXXX: Make this work with React 16, onRow handler has to go to a renderer
class RefTable extends React.Component {
constructor(props) {
super(props);
this.onRow = this.onRow.bind(this);
this.headerRef = null;
this.bodyRef = null;
}
render() {
return (
<Table.Provider columns={columns}>
<Table.Header
ref={header => {
this.headerRef = header
}}
/>
<Table.Body
ref={body => {
this.bodyRef = body
}}
rows={rows}
rowKey="id"
onRow={this.onRow}
/>
</Table.Provider>
);
}
onRow(row, { rowIndex, rowKey }) {
return {
onClick: () => console.log(this.headerRef, this.bodyRef)
};
}
}
<RefTable />
Table.Header
and Table.Body
Rows
Customizing It is possible to customize body behavior on a row level. onRow
prop accepts function (row, { rowIndex, rowKey }) => ({...})
that allows you to set custom attributes per each row.
// XXXXX: Replace onRow with a renderer
class CustomTable extends React.Component {
render() {
return (
<Table.Provider
className="pure-table pure-table-striped"
columns={columns}
>
<Table.Header
onRow={this.onHeaderRow}
/>
<Table.Body
rows={rows}
rowKey="id"
onRow={this.onBodyRow}
/>
</Table.Provider>
);
}
onHeaderRow(row, { rowIndex }) {
return {
onClick: () => console.log('clicked header row', row)
};
}
onBodyRow(row, { rowIndex, rowKey }) {
return {
onClick: () => console.log('clicked body row', row)
};
}
}
<CustomTable />
It's a good idea to define a possible row
handler separately to avoid binding per each render
. If you write the handler inline, it will bind each time render()
is called and reduce performance slightly.
Table
Footer
Customizing It is possible to inject a custom footer like this:
<Table.Provider
className="pure-table pure-table-striped"
columns={columns}
>
<Table.Header />
<Table.Body rows={rows} rowKey="id" />
<tfoot>
<tr>
<td>Show custom rows here</td>
<td>Show custom rows here</td>
</tr>
</tfoot>
</Table.Provider>