How to Set Rows in React-Bootstrap Correctly? - javascript

how do I set the number of cards per row? I need 4 cards to be in one row of mine.
I have been trying for hours.. can't figure out what i do wrong..
I was getting all sorts of compilation errors when i played around with this.
thanks!
:)
import { React } from 'react';
import { Card, Button, CardGroup } from 'react-bootstrap';
import { connect } from 'react-redux';
import { Link } from 'react-router-dom';
const MyDishes = props => {
const { dishes } = props;
return (
<CardGroup style={{display: 'flex', flexDirection: 'row'}}>
{dishes.length > 0 &&
dishes.map(d => (
<Row xs={1} md={2} className="g-4">
{Array.from({ length: 4 }).map((_, idx) => (
<Col>
<Card key={d.id} style={{ width: '100em' }} style={{flex: 1}}>
<Card.Img variant="top" src={d.attributes.picture} />
<Card.Body>
<Card.Title>{d.attributes.name}</Card.Title>
<Card.Text>Possibly some text here</Card.Text>
<Link to={`/dishes/${d.id}`}>
<Button variant="primary">Full Recipe</Button>
</Link>
</Card.Body>
</Card>
</Col>
))}
</Row>
</CardGroup>
);
};
const mapStateToProps = state => {
return {
dishes: state.myDishes
};
};
export default connect(mapStateToProps)(MyDishes);

Above bootstrap 5
<Row className="row-cols-4">
...
</Row>
or any version
<Row className="row-cols-4">
{Array.from({ length: 4 }).map((_, idx) => (
<Col className="col-3">
...
</Col>
</Row>

Related

Each child in a list should have a unique "key" prop. CartScreen replaces item instead of adding when add to cart button is clicked

so I've been having this issue with my web page that im unable to solve on my own. Everything works, however when I add Items to my cart instead of aadding the item it replaces the current item with that one. When I go to inspect my CartScreen it displays this error:
react-jsx-dev-runtime.development.js:87 Warning: Each child in a list should have a unique "key" prop.
Check the render method of CartScreen. See https://reactjs.org/link/warning-keys for more information.
i dont get it because I assumed that I hve a unquie key prop at Line:54 I need help if anyone knows the issue here. Here is my CartScreen code:
`
import { useContext } from 'react';
import { Store } from '../Store';
import { Helmet } from 'react-helmet-async';
import Row from 'react-bootstrap/Row';
import Col from 'react-bootstrap/Col';
import MessageBox from '../components/MessageBox';
import ListGroup from 'react-bootstrap/ListGroup';
import Button from 'react-bootstrap/Button';
import Card from 'react-bootstrap/Card';
import { Link, useNavigate } from 'react-router-dom';
import axios from 'axios';
export default function CartScreen() {
const navigate = useNavigate();
const { state, dispatch: ctxDispatch } = useContext(Store);
const {
cart: { cartItems },
} = state;
const updateCartHandler = async (item, quantity) => {
const { data } = await axios.get(`/api/products/${item._id}`);
if (data.countInStock < quantity) {
window.alert('Sorry. Product is out of stock');
return;
}
ctxDispatch({
type: 'CART_ADD_ITEM',
payload: { ...item, quantity },
});
};
const removeItemHandler = (item) => {
ctxDispatch({ type: 'CART_REMOVE_ITEM', payload: item });
};
const checkoutHandler = () => {
navigate('/signin?redirect=/shipping');
};
return (
<div>
<Helmet>
<title>Shopping Cart</title>
</Helmet>
<h1>Shopping Cart</h1>
<Row>
<Col md={8}>
{cartItems.length === 0 ? (
<MessageBox>
Cart is empty. <Link to="/">Go Shopping</Link>
</MessageBox>
) : (
<ListGroup>
{cartItems.map((item) => (
The key is right here:
<ListGroup.Item key={item._id}>
<Row className="align-items-center">
<Col md={4}>
<img
src={item.image}
alt={item.name}
className="img-fluid rounded img-thumbnail"
></img>{' '}
<Link to={`/product/${item.slug}`}>{item.name}</Link>
</Col>
<Col md={3}>
<Button
onClick={() =>
updateCartHandler(item, item.quantity - 1)
}
variant="light"
disabled={item.quantity === 1}
>
<i className="fas fa-minus-circle"></i>
</Button>{' '}
<span>{item.quantity}</span>{' '}
<Button
variant="light"
onClick={() =>
updateCartHandler(item, item.quantity + 1)
}
disabled={item.quantity === item.countInStock}
>
<i className="fas fa-plus-circle"></i>
</Button>
</Col>
<Col md={3}>${item.price}</Col>
<Col md={2}>
<Button
onClick={() => removeItemHandler(item)}
variant="light"
>
<i className="fas fa-trash"></i>
</Button>
</Col>
</Row>
</ListGroup.Item>
))}
</ListGroup>
)}
</Col>
<Col md={4}>
<Card>
<Card.Body>
<ListGroup variant="flush">
<ListGroup.Item>
<h3>
Subtotal ({cartItems.reduce((a, c) => a + c.quantity, 0)}{' '}
items) : $
{cartItems.reduce((a, c) => a + c.price * c.quantity, 0)}
</h3>
</ListGroup.Item>
<ListGroup.Item>
<div className="d-grid">
<Button
type="button"
variant="primary"
onClick={checkoutHandler}
disabled={cartItems.length === 0}
>
Proceed to Checkout
</Button>
</div>
</ListGroup.Item>
</ListGroup>
</Card.Body>
</Card>
</Col>
</Row>
</div>
);
}
Actually I attempted to follow the instructions from the reactjs.org website on lists-and-keys but it was unsuccessful and I really didnt know how to go about it.
You've got duplicate ids. change it to cartItems.map((item, i) => ...) and use i for the key.

react recursive accordion component throwing an error each child in a list should have a unique key prop

I'm writing custom nested recursive accordion component to display objects, In that component I'm getting an error each child in a list should have a unique key prop, not sure where I need to put the key property
how to resolve the same.
accordion.js:
import React, { useState, useCallback } from 'react'
import { Container, Grid } from '#material-ui/core'
import './styles.css'
function Accodian({ explorer }) {
const [ expand, setExpand ] = useState(false)
const handleExpand = useCallback(() => {
setExpand(prevState => !prevState)
})
if (explorer.children) {
return (
<div style={{ width: '100%' }} className={'tabs'} key={explorer.label}>
{explorer.children ? (
<>
<div className='tab' onClick={handleExpand}>
<label className={ expand ? 'tab-label-expanded' : 'tab-label' }>
{explorer.label}
</label>
</div>
{expand ? (
<Container className='tab-content'>
<Grid container spacing={1}>
{explorer.children.map(child => {
return (
<React.Fragment>
{Array.isArray(child.children) ? (
<Accodian explorer={child}/>
) : (
<Grid item xs={12} sm={6} md={6} lg={4} xl={3}>
<li>
<b>{child.label}</b>{' '}: {child.value}
</li>
</Grid>
)}
</React.Fragment>
)
})}
</Grid>
</Container>
) : null}
</>
) : null}
</div>
)
} else {
return <div style={{ paddingLeft: '20px' }}>{explorer.label}</div>
}
}
export default Accodian
After did many analysis found the place where we can able to apply the key in the component
Solution: <React.Fragment key={child.label}>
import React, { useState, useCallback } from 'react'
import { Container, Grid } from '#material-ui/core'
import './styles.css'
function Accodian({ explorer }) {
const [ expand, setExpand ] = useState(false)
const handleExpand = useCallback(() => {
setExpand(prevState => !prevState)
})
if (explorer.children) {
return (
<div style={{ width: '100%' }} className={'tabs'} key={explorer.label}>
{explorer.children ? (
<>
<div className='tab' onClick={handleExpand}>
<label className={ expand ? 'tab-label-expanded' : 'tab-label' }>
{explorer.label}
</label>
</div>
{expand ? (
<Container className='tab-content'>
<Grid container spacing={1}>
{explorer.children.map(child => {
return (
<React.Fragment key={child.label}> // applied key
{Array.isArray(child.children) ? (
<Accodian explorer={child}/>
) : (
<Grid item xs={12} sm={6} md={6} lg={4} xl={3}>
<li>
<b>{child.label}</b>{' '}: {child.value}
</li>
</Grid>
)}
</React.Fragment>
)
})}
</Grid>
</Container>
) : null}
</>
) : null}
</div>
)
} else {
return <div style={{ paddingLeft: '20px' }}>{explorer.label}</div>
}
}
export default Accodian

Recharts show tooltip on ALL charts on hover

I'm using recharts/ react to visualize some simple data, and running into a wall. I want to show the line + tooltip on ALL the graphs whenever a user hovers over any of the graphs. Been trying to use state or dispatch but running into a wall.
I've attached code snippets for my chart and dashboard files with the attempt at using dispatcher. I dont't know where in chart.js to actually call showTooltip. The functionality I want is to show the tooltips for all charts whenever a user hovers over any single chart. If one tooltip = active, I want all tooltips=active. Any guidance would be super helpful!
chart.js snippet
export default function Chart(props) {
const {state, dispatch} = useContext(AppContext);
const showTooltip = (newValue) => {
dispatch({ type: 'HOVER', data: newValue,});
};
const theme = createMuiTheme({
palette: {
primary: {
main: '#041f35'
},
secondary: {
main: '#5dc5e7'
}
}
});
return (
<React.Fragment>
<MuiThemeProvider theme={theme}>
<Title>{props.title}</Title>
<ResponsiveContainer width="100%" height="100%">
<LineChart
width={500}
height={300}
data={data}
margin={{
top: 5,
right: 5,
left: -35,
bottom: 5,
}}
>
<XAxis dataKey="time" />
<YAxis axisLine={false} tickLine={false}/>
<Tooltip />
<CartesianGrid vertical={false} stroke="#d3d3d3"/>
<Line type="monotone" dataKey="mktplace1" stroke={theme.palette.primary.main} activeDot={{ r: 8 }} />
<Line type="monotone" dataKey="mktplace2" stroke={theme.palette.secondary.main} />
</LineChart>
</ResponsiveContainer>
</MuiThemeProvider>
</React.Fragment>
);
}
dashboard.js file snippet
export const AppContext = React.createContext();
// Set up Initial State
const initialState = {
active: new Boolean(false),
};
function reducer(state, action) {
switch (action.type) {
case 'HOVER':
return {
active: new Boolean(true)
};
default:
return initialState;
}
}
export default function Dashboard() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<div className={classes.root}>
<CssBaseline />
<main className={classes.content}>
<Container maxWidth="lg" className={classes.container}>
<Grid container spacing={2}>
{/* Chart */}
<Grid item xs={12} sm={12} md={6} lg={6} xl={6}>
<Paper className={fixedHeightPaper}>
<AppContext.Provider value={{ state, dispatch }}>
<Chart title="Sales by Marketplace"/>
</AppContext.Provider>
</Paper>
</Grid>
<Grid item xs={12} sm={12} md={6} lg={6} xl={6}>
<Paper className={fixedHeightPaper}>
<AppContext.Provider value={{ state, dispatch }}>
<Chart title="Sales by Marketplace"/>
</AppContext.Provider>
</Paper>
</Grid>
<Grid item xs={12} sm={12} md={6} lg={6} xl={6}>
<Paper className={fixedHeightPaper}>
<AppContext.Provider value={{ state, dispatch }}>
<Chart title="Sales by Marketplace"/>
</AppContext.Provider>
</Paper>
</Grid>
<Grid item xs={12} sm={12} md={6} lg={6} xl={6}>
<Paper className={fixedHeightPaper}>
<AppContext.Provider value={{ state, dispatch }}>
<Chart title="Sales by Marketplace"/>
</AppContext.Provider>
</Paper>
</Grid>
</Grid>
</Container>
</main>
</div>
);
}
I know this was a long time ago, but there is a "syncId" property to put on your chart. All charts with the same syncId will show tooltips at the same time.

Accessing functionality from parent component in child component ReactJS

I have working code in App.jsx. Everything is working when this written together in one file.
const App = props => {
const [cartProducts, setCartProducts] = useState([]);
const [products, setProducts] = useState(getProducts());
//const [searchValue, setSearchValue] = useState();
const handleAddProductToCart = productID => {
setCartProducts([...cartProducts, productID]);
};
const handleRemoveFromCart = productID => {
const newCartProducts = cartProducts.filter(id => id !== productID);
setCartProducts(newCartProducts);
};
/*const filterItems = ({ description, title }) => {
return title.toLocaleLowerCase().indexOf(searchValue.toLocaleLowerCase())
|| description.toLocaleLowerCase().indexOf(searchValue.toLocaleLowerCase())
}*/
return (
<>
<Header/>
<Search/>
<Sidebar/>
<div>
{products.map(product => {
const { id, title, description, image } = product;
let haveInCart = false;
cartProducts.forEach(productID => {
if (productID === id) {
haveInCart = true;
}
});
return (
<Card key={id} className="item-card">
<CardImg src={image} alt={title} className="item-img" style={{ height: '260px' }} />
<CardBody style={{ border: 'none' }} className="custom-card-body">
<CardTitle style={{ border: 'none' }} className="custom-card-title">{title}</CardTitle>
<CardText style={{ border: 'none' }} className="custom-card-text">{description}</CardText>
<FontAwesomeIcon icon={faCartPlus} className="add-icon" onClick={() => handleAddProductToCart(id)} />
</CardBody>
</Card>
);
})}
<h2>Your Cart</h2>
{cartProducts.length > 0
? cartProducts.map(productID => {
const productIndex = products.findIndex(product => {
return product.id === productID;
});
let { id, title, image } = products[productIndex];
return (
<Card key={id} className="item-card">
<CardImg src={image} alt={title} className="item-img" style={{ height: '260px' }} />
<CardBody style={{ border: 'none' }} className="custom-card-body">
<CardTitle style={{ border: 'none' }} className="custom-card-title">{title}</CardTitle>
<FontAwesomeIcon icon={faTrash} className="remove-icon" onClick={() => handleRemoveFromCart(id)} />
</CardBody>
</Card>
);
})
: "Yor Cart is Empty :("}
</div>
</>
)
}
export default App;
I want to put product Card and cart Card into it's own component. And when I'm doing it, like this
const Product = ({product}) => {
const { id, title, description, image } = product;
return (
<Card key={id} className="item-card">
<CardImg src={image} alt={title} className="item-img" style={{ height: '260px' }} />
<CardBody style={{ border: 'none' }} className="custom-card-body">
<CardTitle style={{ border: 'none' }} className="custom-card-title">{title}</CardTitle>
<CardText style={{ border: 'none' }} className="custom-card-text">{description}</CardText>
<FontAwesomeIcon icon={faCartPlus} className="add-icon" /*onClick={() => handleAddProductToCart(id)}*/ />
</CardBody>
</Card>
)
}
I'm not getting properties of product in my Card. I want to make my code better organized and save it's functionality. How to access those states from Product and Cart component?
EDIT
Here's the link to codesandbox
https://codesandbox.io/s/late-cookies-r2inh?file=/src/App.jsx&fbclid=IwAR38tcE39tVL51YpG4_6A1HRz-kth1GSIocQWMPrU3QXepc5CHUNn-ZqiG8
EDIT 2 How I can make items in cart be displaying beside Product component, on the left side? Should I create entire Cart component for it?
Your Product.jsx file should look like this:
import React from "react";
import { FontAwesomeIcon } from "#fortawesome/react-fontawesome";
import { faCartPlus } from "#fortawesome/free-solid-svg-icons";
import Card from "react-bootstrap/Card";
import CardBody from "react-bootstrap/Card";
import CardImg from "react-bootstrap/CardImg";
import CardTitle from "react-bootstrap/Card";
import CardText from "react-bootstrap/Card";
const Product = ({ product, handleAddProductToCart }) => {
const { id, title, description, image } = product;
return (
<Card key={id} className="item-card">
<CardImg
src={image}
alt={title}
className="item-img"
style={{ height: "260px" }}
/>
<CardBody style={{ border: "none" }} className="custom-card-body">
<CardTitle style={{ border: "none" }} className="custom-card-title">
{title}
</CardTitle>
<CardText style={{ border: "none" }} className="custom-card-text">
{description}
</CardText>
<FontAwesomeIcon
icon={faCartPlus}
className="add-icon"
onClick={() => handleAddProductToCart(id)}
/>
</CardBody>
</Card>
);
};
export default Product;
And in your App.jsx you can map the products array like this:
{products.map((product) => (
<Product
product={product}
key={product.id}
handleAddProductToCart={handleAddProductToCart}
/>
))}
EDIT:
https://codesandbox.io/s/determined-swartz-5q2fo
I edited the codesandbox, i made the Product component accept both add and remove product callback and the "haveInCart" prop. It will decide which icon and which callback to use base on that prop. I'm not sure about this approch tho

props don't have the right data in reactjs

i use a firebase database and i take data from this base into JSON format. With this data i am using map function and i want to render my data into other components. My code is as shown below. The first component
function Products() {
const [url, setUrl] = useState([]);
useEffect(() => {
async function asyncCall() {
const myurl = await axios.get("i put a example link here:mydata.json")
setUrl(myurl.data)
}
asyncCall();
},[]);
return (
<Row>
{url.map((url => (
<Col key={url.id} sm={12} md={6} lg={4} xl={3}>
<Bags url={url} />
</Col>
)
))}
</Row>
)
}
The second component that i want to render my data
function Bags(props) {
return (
<Row>
<CardDeck>
<Col sm={14} md={8} lg={6}>
<Card className='my-3 p-3 rounded'>
{
props.url ? (
<div>
<Card.Img variant="top" src={ props.url.img || 'holder.js/100px160'} />
<Card.Body>
<Card.Title> {props.url.name} </Card.Title>
<Card.Text>
This is the greatest albums of rock band Pearl Jam according to Nikolas
</Card.Text>
</Card.Body>
</div>
) : (
<div className="myprogress">
<CircularProgress color="secondary" />
</div>
)
}
</Card>
</Col>
</CardDeck>
</Row>
)
}
With the second component i want to produce the number of Bootstrap-React Cards depending of the number of data i have. For example if i have 6 elements into my JSON file i want in the second component to produce 6 react-bootstrap Cards and print for each some informations like the name.
With the above code i accomplished to pass the props but the props that i console.log is not my data. This is what i get in my console when i
console.log(props)
Can anyone tell how i can pass my data correctly or suggest a better way to do that.
I hope my question is understood. I can give more information i anyone wants
I think this is what you are trying to achieve:
function Products() {
const [url, setUrl] = useState([]);
useEffect(() => {
async function asyncCall() {
const myurl = await axios.get("i put a example link here:mydata.json");
setUrl(myurl.data);
}
asyncCall();
}, []);
return (
<Row>
{/*{ {url.map((url => ( */}
{/* the url in the arrow function was shadowing the url array that you were trying to pass to the bags componenet */}
<Col key={url.id} sm={12} md={6} lg={4} xl={3}>
<Bags url={url} />
</Col>
{/* )
))} */}
</Row>
);
}
function Bags(props) {
return (
<Row>
<CardDeck>
<Col sm={14} md={8} lg={6}>
<Card className="my-3 p-3 rounded">
{props.url.length > 0 ? (
props.url.map((el) => (
<div>
<Card.Img
variant="top"
src={el.img || "holder.js/100px160"}
/>
<Card.Body>
<Card.Title> {el.name} </Card.Title>
<Card.Text>
This is the greatest albums of rock band Pearl Jam
according to Nikolas
</Card.Text>
</Card.Body>
</div>
))
) : (
<div className="myprogress">
<CircularProgress color="secondary" />
</div>
)}
</Card>
</Col>
</CardDeck>
</Row>
);
}
can you please confirm the results?
Try this and tell me if it works
import React, { useEffect, useState } from "react";
import axios from "axios";
import "./styles.css";
export default function App() {
const [url, setUrl] = useState([]);
useEffect(() => {
async function asyncCall() {
const response = await fetch(
"https://mysiteproject-8adcf.firebaseio.com/products.json"
);
const responseJson = await response.json();
console.log(responseJson);
setUrl(responseJson);
}
asyncCall();
}, []);
return (
<div>
{url.map((url => (
<Col key={url.id} sm={12} md={6} lg={4} xl={3}>
<Bags url={url} />
</Col>
)
))}
</div>
);
}
I almost solved the problem with this implementation
function Bags() {
const [url, setUrl] = useState([]);
//const [myfinal,setFinal] = useState([]);
useEffect(() => {
async function asyncCall() {
const myurl = await axios.get("https://mysiteproject-8adcf.firebaseio.com/products.json")
setUrl(myurl.data)
}
asyncCall();
},[]);
if (url) {
//let myvar = url;
//console.log(myvar.img);
//console.log(myvar);
url.map((url) => console.log(url.img));
}
//console.log()
return (
<Row>
<CardDeck>
<Col sm={14} md={8} lg={6}>
<Card className='my-3 p-3 rounded'>
{url.length > 0 ? (
url.map((el) => (
<div>
<Card.Img
variant="top"
src={el.img || "holder.js/100px160"}
/>
<Card.Body>
<Card.Title> {el.name} </Card.Title>
<Card.Text>
This is the greatest albums of rock band Pearl Jam
according to Nikolas
</Card.Text>
</Card.Body>
</div>
))
) : (
<div className="myprogress">
<CircularProgress color="secondary" />
</div>
)}
</Card>
</Col>
</CardDeck>
</Row>
)
}
I don't know if this implementation is optimal

Categories