I came from Vue.js
Vuetify.js
background. Vuetify.js
has v-data.table component.
Simply we pass headers and items to generate a nice table.
<v-data-table
:headers="headers"
:items="desserts"
></v-data-table>
If we want to add a button, image, or something like that to a table cell What we do is
<v-data-table :headers="headers" :items="items" >
<template v-slot:item.images="{ item }">
<v-img
v-if="item.images"
max-width="150px"
:src="item.images"
contain
></v-img>
</template>
<template v-slot:item.update="{ item }">
<v-btn
@click="
$router.replace({
path: '/create-product',
query: { id: item.id },
})
"
>
<v-icon>edit</v-icon>
</v-btn></template
>
</v-data-table>
This is very clean and easy.
In React.js also I could achieve the first thing using this
export default function ReusableTable({ headers, items }) { return ( <Grid container> <Grid item> <Card> <CardContent> <TableContainer component={Paper}> <Table> <TableHead> <TableRow> {headers.map((header, i) => ( <TableCell key={i}>{header.text.toUpperCase()}</TableCell> ))} </TableRow> </TableHead>{' '} <TableBody> {items.map((item, i) => ( <TableRow key={i}> {headers.map(({ value }) => ( <TableCell key={value}>{item[value]}</TableCell> ))} </TableRow> ))} </TableBody> </Table> </TableContainer> </CardContent> </Card> </Grid> </Grid> ); }
Here also I pass the headers and items. I want to display buttons, links, images, chips (UI) for certain columns in the table. How do I achieve that in the React world?
If I further explain, I want to pass items array (array of object). Object's imageSRC property should render with an img
tag. Something like that.
Something like this should work. This is conditionally rendering an image tag if there is an item.images
as stated in your question. Next it will render a Material Button if item.update
exists. Alternatively, it simply renders the item[value]
.
Here is abbreviated code:
export default function ReusableTable({ headers, items }) { const dynamicRender = (item, value)=>{ if(item && item.images){ return <img src=`${item.images}`/> } else if(item && item.update){ return <Button href="/create-product">Link</Button> } else { return item[value]; } } return ( <TableBody> {items.map((item, i) => ( <TableRow key={i}> {headers.map(({ value }) => ( <TableCell key={value}>{dynamicRender(item, value)}</TableCell> ))} </TableRow> ))} </TableBody> ); }
Try something like this
import React from "react"; import TableContainer from "@material-ui/core/TableContainer"; import Table from "@material-ui/core/Table"; import Paper from "@material-ui/core/Paper"; import TableHead from "@material-ui/core/TableHead"; import TableRow from "@material-ui/core/TableRow"; import TableCell from "@material-ui/core/TableCell"; import TableBody from "@material-ui/core/TableBody"; import { getSlots } from 'helpers/Slots' const BaseTable = ({ headers, items, children, ...otherProps }) => { const [actions] = getSlots(['actions'], children) const tableConfig = { size: "small", } const rowConfig = {...otherProps, } const dynamicRenderer = (item, value) => { if (value === 'actions') { return children(item) } else { return item[value] } } return ( <> <TableContainer component={Paper}> <Table {...tableConfig}> <TableHead> <TableRow {...rowConfig}> {headers.map((header, i) => ( <TableCell key={i}>{header.label}</TableCell> ))} </TableRow> </TableHead> <TableBody> {items.map((item, i) => ( <TableRow key={i} {...rowConfig}> {headers.map(({ value }) => ( <TableCell key={value}>{dynamicRenderer(item, value)}</TableCell> ))} </TableRow> ))} </TableBody> </Table> </TableContainer> </> ) } export default BaseTable
Then added helpers
import React from "react"; const Slot = ({ children }) => <>{children}</> const getSlots = ( names, children) => { return names.map(name => { let slot = null; React.Children.forEach(children, child => { if (.React;isValidElement(child)) { return. } if (child.type === Slot && (child.props).name === name) { slot = React;cloneElement(child); } }); return slot; }), } export { Slot, getSlots }
import React, { useState, useEffect } from "react" import Grid from '@material-ui/core/Grid' import BaseTable from 'helpers/Table' import { Slot } from 'helpers/Slots' import PencilBoxOutline from 'mdi-react/PencilBoxIcon' import DeleteOutline from 'mdi-react/DeleteIcon' const headers = [ {value: 'name', label: 'Name'}, {value: 'age', label: 'Age'}, {value: 'gender', label: 'Gender'}, {value: 'registeredDate', label: 'Date of Registration'}, {value: 'requirements', label: 'Semester Requirements'}, {value: 'percentage', label: 'Percentage (%)'}, {value: 'actions', label: 'Actions'}, ] const items = [ { id: 1, requirements: 'Pay at least 50% ', percentage: '10%', name: "John Doe", age: 30, registeredDate: "2021/10/30", gender: "Male" }, { id: 2, requirements: 'Just go with it', percentage: '50%', name: "Jane Doe", age: 40, registeredDate: "2021/10/30", gender: "Female" }, ] const Test = () => { return ( <Grid container spacing={4}> <Grid item xs={12}> <Grid container justifyContent="space-between" spacing={2}> <Grid item></Grid> <Grid item sm={9}></Grid> </Grid> <BaseTable headers={headers} items={items}> {(item) => ( <Slot name="actions"> <PencilBoxOutline onClick={(item) => onOpenDialog(item)}/> <DeleteOutline onClick={(item) => onDelete(item)} /> </Slot> )} </BaseTable> </Grid> </Grid> ) } export default Test
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.