vamsiampolu vamsiampolu - 3 months ago 23
Javascript Question

Encapsulating material-ui into custom components

I am having a bit of trouble with the

material-ui
Table component. I seperated the table logic into a header and body component and within body, added a different component for each row

export const PRODUCTS = [
{category: 'Sporting Goods', price: '$49.99', stocked: true, name: 'Football'},
{category: 'Sporting Goods', price: '$9.99', stocked: true, name: 'Baseball'},
{category: 'Sporting Goods', price: '$29.99', stocked: false, name: 'Basketball'},
{category: 'Electronics', price: '$99.99', stocked: true, name: 'iPod Touch'},
{category: 'Electronics', price: '$399.99', stocked: false, name: 'iPhone 5'},
{category: 'Electronics', price: '$199.99', stocked: true, name: 'Nexus 7'}
]

export const ProductCategoryRow = ({
product: {
name,
price
}
}) => (<TableRow>
<TableRowColumn>
{name}
</TableRowColumn>
<TableRowColumn>
{price}
</TableRowColumn>
</TableRow>
)

const ProductHeader = () => (<TableHeader>
<TableRow>
<TableHeaderColumn>
Name
</TableHeaderColumn>
<TableHeaderColumn>
Price
</TableHeaderColumn>
</TableRow>
</TableHeader>
)

export const ProductTableBody = (props) => {
bin.log(props)
const Products = props.products.map(product => (<ProductRow product={product} />))
console.log(Products)
return Products
}


The product table component is composed of these components:

//this does not work, the components are passed down to children and nothing happens.
const ProductTable = (props) => (
<Table>
<ProductHeader/>
<ProductTableBody products={props.products}/>
</Table>
)


I have a webpack bin here that you can take a look at. I have commented out the
ProductTable
that does not work.

Answer

The <Table> implementation relies on its direct children having a <TableHeader>, a <TableBody>, and optionally a <TableFooter> component.

If it does not find at least a <TableHeader> and a <TableBody>, then it simply does not render anything in its header/body. This is what is happening in your situation.

One way you can get around this is to keep the <TableBody> and <TableHeader> with the <Table>, but use some helper functions to achieve a similar level of abstraction you desire.

const ProductCategoryRow = (props) => {
    const { name, price } = props.product

    return (
        <TableRow>
            <TableRowColumn>
              {name}
            </TableRowColumn>
            <TableRowColumn>
              {price}
            </TableRowColumn>
        </TableRow>
    )
}


function createHeaderColumns(columnNames) {
    return columnNames.map(name => <TableHeaderColumn>{name}</TableHeaderColumn>)
}

function createTableRows(rows) {
    return rows.map(row => <ProductCategoryRow product={row} />)
}

const ProductTable = (props) => {

    const headerColumns = createHeaderColumns(props.columnNames)
    const tableRows = createTableRows(props.products)

    return (
            <Table>
                <TableHeader>
                    <TableRow>
                        {headerColumns}
                    </TableRow>
                </TableHeader>
                <TableBody>
                    {tableRows}
                </TableBody>
            </Table>
    )
}