I want to create a table in my React functional component using hooks and the react material ui. I have an array of strings and I want to create a chip for each string in a table cell like so:
<TableCell>
<Chip
key={index}
className={classes.chips}
size="large"
label={user}
icon={<AccountCircleIcon className={classes.closeIcon}/>}
/>
</TableCell>
I display an array of chips with
<div className={classes.chipContainer}> {Object.values(selectedUsersToDelete).map((user, index) => {
return (
<TableRow>
<TableCell>
<Chip
key={index}
className={classes.chips}
size="large"
label={user}
icon={<AccountCircleIcon className={classes.closeIcon}/>}
/>
</TableCell><TableCell>
<Chip
key={index}
className={classes.chips}
size="large"
label={user}
icon={<AccountCircleIcon className={classes.closeIcon}/>}
/>
</TableCell>
</TableRow>
)
})}
</div>
where selectedUsersToDelete is the value of useState.
I have tried every way of looping over the values in selectedUsersToDelete, but I cannot get react to render the table with the table rows 5 cells wide!
Also adding a deleteIcon and deletehandler to the Chip breaks them.
I'm trying to adapt this tutorial to use hooks: tut
import React, { useState, useEffect } from 'react';
// You'll need to add correct paths below
import AccountCircleIcon from './AccountCircleIcon';
import TableCell from './TableCell';
import TableRow from './TableRow';
import Chip from './Chip';
const ChipContainer = props => {
// State is initialized here
const [selectedUsersToDelete, setSelectedUsersToDelete] = useState([]);
// Props destructred
const { classes } = props;
// Just an example showing how you can set state once componnent has mounted
useEffect(
() =>
void setSelectedUsersToDelete([
'user1',
'user2',
'user3',
'user4',
'user5'
]),
[]
);
return (
<div className={classes.chipContainer}>
<TableRow>
{selectedUsersToDelete.map((user, index) => (
<TableCell>
<Chip
key={index}
className={classes.chips}
size="large"
label={user}
icon={<AccountCircleIcon className={classes.closeIcon} />}
/>
</TableCell>
))}
</TableRow>
</div>
);
};
export default ChipContainer;
Related
I am using react virtualize table with many sub components in it and have very bad performance when rendering it.
it gets more aweful after scrolling, clicking buttons...
<TableContainer className={classes.table}>
<AutoSizer>
{({ height, width }) => (
<Table
height={height}
width={width}
rowHeight={64}
headerHeight={84}
rowCount={!isLoading ? tableRowsData.length : LOADING_ROWS_COUNT}
gridStyle={{
direction: 'inherit',
}}
rowGetter={({ index }) => getRowRow(index)}
className={classes.table}
rowClassName={getRowClassName}
noRowsRenderer={noRowsRendererHandler}
disableHeader={showEmptyState}
>
{Object.keys(headersConfig).map((key) => {
return (
<Column
key={key}
headerRenderer={({dataKey}) => headersConfig[dataKey].content}
cellRenderer={({ cellData }) => cellData}
dataKey={key}
width={headersConfig[key].width}
/>
)
})}
</Table>
)}
</AutoSizer>
</TableContainer>
the headerConfig is an object with all the column components.
how can I use this table wiser? how can I prevent many unnecessary re-renders?
am I need to use the rowRenderer prop? if so, can I get an example or a link to understand the implementation?
tnx
cheers
I'm using React Bootstrap and am pulling data from an API using Axios. I'm trying to display the data from that API in bootstrap Card / CarDeck components. I have most of it working using the code below but I'm having problems with the layout.
I'd like to be able to have the card deck be responsive and show a flexible number of cards per row depending on the screen size. At the moment if there are lots of items in the response each card is ridiculously thin and can't be viewed. What is the correct way to do this?
import React, { useState, useEffect } from "react";
import CardDeck from "react-bootstrap/CardDeck";
import Card from "react-bootstrap/Card";
import axios from "axios";
import Container from "react-bootstrap/Container";
const CardColumns = () => {
const [cardInfo, setData] = useState([]);
console.log(cardInfo);
useEffect(() => {
axios
.get(
"https://webhooks.mongodb-realm.com/api/client/v2.0/app/cards-fvyrn/service/Cards/incoming_webhook/getAllCards"
)
.then((response) => {
setData(response.data);
console.log(response.data);
})
.catch(function (error) {
console.log(error);
});
}, []);
const renderCard = (card, index) => {
return (
<Card style={{ width: "18rem" }} key={index} className="box">
<Card.Img variant="top" src="holder.js/100px180" src={card.image} />
<Card.Body>
<Card.Title>
{index} - {card.manufacturer}
</Card.Title>
<Card.Text>{card.player}</Card.Text>
</Card.Body>
</Card>
);
};
return <CardDeck>{cardInfo.map(renderCard)}</CardDeck>;
};
export default CardColumns;
In the end this is the solution I went with the below. Key I think were:
Wrapping the cardDeck in <Container> and then wrapping the cards with <Col className="container-fluid mt-4">:
`
const renderCard = (card, index) => {
return (`
<Col className="container-fluid mt-4">
{/* <Card key={index} className="box"> */}
<Card style={{ width: "18rem" }} key={index} className="box">
<Card.Header>
{card.brand} - {card.series}
</Card.Header>
<Card.Img variant="top" src={card.front_image} fluid />
<Card.Body>
<Card.Title>
{card.player} (#
{card.card_number.$numberDouble}) {card.variation}
</Card.Title>
{/* <Card.Text className="d-flex">{card.player}</Card.Text> */}
{/* <Card.Text>{card.player}</Card.Text> */}
</Card.Body>
<ListGroup className="list-group-flush">
<ListGroupItem>
Print Run - {card.print_run.$numberDouble}
</ListGroupItem>
<ListGroupItem>Career Stage - {card.career_stage} </ListGroupItem>
<ListGroupItem>For Trade - {card.forTrade}</ListGroupItem>
</ListGroup>
<Card.Footer className="text-muted">{card.team}</Card.Footer>
</Card>
</Col>
//{/* </Col> */}
);
};
return (
<Container>
<Button variant="primary">Filter By Brand</Button>{" "}
<Button variant="primary">Filter By Player</Button>{" "}
<Button variant="primary">Filter By Team</Button>
<CardDeck>{cardInfo.map(renderCard)}</CardDeck>
</Container>
);`
Here are my suggestions for this issue:
Each card should have a min-width to ensure that they do not shrink below a certain amount. So instead of width: "18rem" try min-width: "18rem". If your CSS is properly set up it should cause other cards to overflow to the next row.
You can make use of media-queries or grid layout as mentioned to determine how many cards you want to show for various screen types based on their varying widths say see this link media-query-breakpoints react-bootstrap-grid
Also you can try using CSS flexbox layout, I have an article on this CSS Flex Box
Try to use a col-'n' to each card instead of a fix width.
...
import { Card, Col } from 'react-bootstrap';
...
<Col md="n"> // n must be your desired width like
<Card key={index} className="box">
...
</Col>
You can see more at: Bootstrap Card Sizing
On a list view with few columns, the columns are very wide. I'd like to limit the width of at least some of these columns (except the last one):
Still trying to come up to speed on react-admin, react, and material-ui. I'm sure there's some styling involved. Could someone please point me in the right direction? Thanks.
UPDATE:
I added the style as Jozef suggested but no change. Here's what it looks like in Inspect:
There are two options to customize width of cells.
If you want to set width evenly you can change table-layout of Datagrid
<Datagrid style={{tableLayout: 'fixed'}} rowClick="edit">
<TextField source="sourceName" />
<BooleanField source="active" />
<TextField source="organizationName" />
</Datagrid>
If it is not enough, well, we have to create our custom Datagrid with all of its dependencies so we can pass to TableCell component specific width. Be it percent or px value. This is not very well documented so you have to rely on source code which is in ra-ui-materialui
Here's the example
import {
Datagrid,
DatagridBody,
DatagridCell,
TextField,
BooleanField
} from 'react-admin';
import Checkbox from '#material-ui/core/Checkbox';
import TableCell from '#material-ui/core/TableCell';
import TableRow from '#material-ui/core/TableRow';
const CustomDatagridRow = ({ record, resource, id, onToggleItem, children, selected, basePath }) => (
<TableRow key={id}>
<TableCell style={{width="10%"}} padding="none">
{record.selectable && <Checkbox
checked={selected}
onClick={() => onToggleItem(id)}
/>}
</TableCell>
{React.Children.map(children, field => (
<TableCell style={{width: field.props.width}} key={`${id}-${field.props.source}`}>
{React.cloneElement(field, {
record,
basePath,
resource,
})}
</TableCell>
))}
</TableRow>
);
const CustomDatagridBody = props => <DatagridBody {...props} row={<CustomDatagridRow />} />;
const CustomDatagrid = props => <Datagrid {...props} body={<CustomDatagridBody />} />;
<CustomDatagrid style={{tableLayout: 'fixed'}} rowClick="edit">
<TextField width="20%" source="sourceName" />
<BooleanField width="20%" source="active" />
<TextField width="50%" source="organizationName" />
</CustomDatagrid>
I'm using Material-UI to build a table that collapses after add more than 3 rows, but it changes its layout when open the collapsed table.
[enter image description here][1]
Creating rows
createRowFrame=(array,num)=>{
return array.map(frameObject=>{
return(
<MuiThemeProvider theme={theme}>
<TableRow key={frameObject.frame.id} style={num===2?{backgroundColor:"#F1D3D3"}:{}}>
<TableCell>1</TableCell>
<TableCell>{frameObject.frame.name}{frameObject.hipsterFrame !== null && (" / "+frameObject.hipsterFrame.name)}</TableCell>
<TableCell><DeleteIcon className={this.props.classes.icon} onClick={()=>{this.props.removeOneFrame(frameObject.frame.id)}}/></TableCell>
</TableRow>
</MuiThemeProvider>
)
})
}
Creating the Collapse Table (conditionaly)
createTablePart=(frameArray, brand)=>{
var remainingCredit = this.props.credits[brand+"Credit"] - frameArray.length
var allowedFrames
var overFrames
if(remainingCredit<0){
allowedFrames = frameArray.slice(0,this.props.credits[brand+"Credit"])
overFrames = frameArray.slice(this.props.credits[brand+"Credit"], frameArray.length)
} else {
allowedFrames=frameArray
overFrames=[]
}
console.log(allowedFrames)
console.log(overFrames)
if(frameArray.length>3){
const {classes, t} = this.props;
return(
<React.Fragment>
<MuiThemeProvider theme={theme}>
<TableRow onClick={()=>this.handleClickOpen(brand+"Open",this.state[brand+"Open"])}>
<TableCell>{frameArray.length}</TableCell>
<TableCell>{brand.toUpperCase()}</TableCell>
<TableCell>{this.state[brand+"Open"] ? <ExpandLess /> : <ExpandMore />}</TableCell>
</TableRow>
<Collapse in={this.state[brand+"Open"]} timeout="auto" unmountOnExit>
<div className={classes.collapsedTable}>
{this.createRowFrame(allowedFrames,1)}
{this.createRowFrame(overFrames,2)}
</div>
</Collapse>
</MuiThemeProvider>
</React.Fragment>
)
} else {
return (
<React.Fragment>
{this.createRowFrame(allowedFrames,1)}
{this.createRowFrame(overFrames,2)}
</React.Fragment>
)
}
}
I expected the table just collapse but still obey the columns.
I think you could avoid using Collapse completely and just conditionally show your new rows programmatically. For example, you would replace this part of your code:
<Collapse in={this.state[brand+"Open"]} timeout="auto" unmountOnExit>
<div className={classes.collapsedTable}>
{this.createRowFrame(allowedFrames,1)}
{this.createRowFrame(overFrames,2)}
</div>
</Collapse>
with:
this.state[brand+"Open"] && <>{Here put your new created row without the div }</>
The syntax is probably incorrect but I think this may be of some help.
How does one disable the input box here, depending on whether a checkbox has been checked or not?
I have verified the checked property - it is in working order (shows true or false boolean values).
However, I can't seem to get the disabled property in Input to work.
Below is my code:
import React from 'react';
import { Button, Checkbox, Input, List } from 'semantic-ui-react'
import PropTypes from 'prop-types';
const CategoryCheckBox = ({ type = 'checkbox', name, mylabel, checked, onChange }) => (
<React.Fragment>
<List horizontal relaxed>
<List.Item>
<Checkbox style={{ paddingLeft:"1em", paddingBottom: "1em" }} label={mylabel} checked={checked} onChange={onChange} />
<List.Content>
<Input style={{ maxWidth:"9em", paddingLeft:"1em" }} size='mini' focus placeholder='Min' disabled={checked === true ? true : false} />
<Input style={{ maxWidth:"9em", paddingLeft:"1em" }} size='mini' focus placeholder='Max' />
</List.Content>
</List.Item>
</List>
</React.Fragment>
);
CategoryCheckBox.propTypes = {
type: PropTypes.string,
name: PropTypes.string.isRequired,
mylabel: PropTypes.string.isRequired,
checked: PropTypes.bool,
onChange: PropTypes.func.isRequired,
}
export default CategoryCheckBox;
From the main program,
The component is called with the below parameters:
<CategoryCheckBox name={item.value} mylabel={item.text} checked={this.state.checkedItems.get(item.value)} onChange={this.handleChange} />
Below is my screenshot for the component along with React debugger showing the checked value.
Any Help will be highly appreciated.
Tried to set up most of the important code - Newbie to React myself. Can't get the index.js in the working order. But it gives you a good idea of my code https://codesandbox.io/embed/2pyoxpr6rn?fontsize=14
Changes:
1- You are not assigning the name to CheckBox element in CategoryCheckBox, add name here:
<Checkbox
style={{ paddingLeft: "1em", paddingBottom: "1em" }}
label={mylabel}
// ↓↓↓↓↓↓↓↓ here
name={name}
checked={checked}
onChange={onChange}
/>
2- Add disable condition for Max input field also:
<Input
style={{ maxWidth: "9em", paddingLeft: "1em" }}
size="mini"
focus
placeholder="Max"
// ↓↓↓↓↓↓↓↓ here
disabled={!checked}
/>
3- Most importantly, You are storing data in states in App component so it needs to be a class component.
Check Working Codesandbox with all these changes.
After looking at your code the problem is with your app component. Your app component has a state and therefore cannot be a stateless functional component. Your App component should look something like this.
import React from "react";
import ReactDOM from "react-dom";
import { Checkbox, Label, Header, Card, Form, Button, Container, Icon, Step, Select, Dropdown, List } from 'semantic-ui-react';
import womensBoutiqueOptions from "./womensBoutiqueOptions";
import CategoryCheckBox from "./CategoryCheckBox";
import "./styles.css";
class App() extends React.Component {
state = {
date: new Date(),
time: '10:00',
checkedItems: new Map()
}
handleChange(e) {
const item = e.target.name;
const isChecked = e.target.checked;
this.setState(prevState => ({ checkedItems: prevState.checkedItems.set(item, isChecked) }));
}
render() {
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<Form size="large" key="large">
<h4 className="ui dividing header">Womens Information</h4>
<Form.Group widths='equal'>
<Form.Field>
<React.Fragment>
<List horizontal >
{
womensBoutiqueOptions.map(item => (
<List.Item key={item.key}>
<List.Content>
<CategoryCheckBox name={item.value} mylabel={item.text} checked={this.state.checkedItems.get(item.value)} onChange={this.handleChange} />
</List.Content>
</List.Item>
))
}
</List>
</React.Fragment>
</Form.Field>
</Form.Group>
</Form>
</div>
)
}
);
}
Check out the react documentation for some more information on why