How to automatically arrange cards in rows and columns? - reactjs

Im trying to create a interactive user interface in ReactJS, using react-bootstrap. Im using cards and CardGroup. I need a way to automatically arrange the cards in new rows. Something like three cards per row, and if I have more than three, create a new row for the 4th card.
import React, { Component } from 'react';
import {Card,CardGroup} from 'react-bootstrap';
import {Button} from 'react-bootstrap';
const Items = ({items}) => {
return (
<>
<container>
<row>
<CardGroup>
{items.map((item) => (
<Card style={{ width: '18rem' }}>
<Card.Body>
<Card.Title>{item.NOME}</Card.Title>
<Card.Subtitle className="mb-2 text-muted">{item.CATEGORIA}</Card.Subtitle>
<Card.Text>
{item.DESCRICAO}
</Card.Text>
<Card.Link href="#">Card Link</Card.Link>
<Card.Link href="#">Another Link</Card.Link>
</Card.Body>
</Card>
))}
</CardGroup>
</row>
</container>
</>
)
};
export default Items

You could create an array with groups of 3 cards and then iterate over them:
const arr = var x = arr.reduce((item, key, index) => (index % 3 == 0 ? item.push([key]) : item[item.length-1].push(key)) && item, []);
const Items = ({items}) => (
<>
<container>
{arr.map(group => (
<row>
<CardGroup>
{group.map(card => (
<Card style={{ width: '18rem' }}>
<Card.Body>
<Card.Title>{item.NOME}</Card.Title>
<Card.Subtitle className="mb-2 text-muted">{item.CATEGORIA}</Card.Subtitle>
<Card.Text>{item.DESCRICAO}</Card.Text>
<Card.Link href="#">Card Link</Card.Link>
<Card.Link href="#">Another Link</Card.Link>
</Card.Body>
</Card>
))}
</CardGroup>
</row>
))}
</container>
</>
);
I haven't tested this code, but it should work...

Related

When I click the Recipe button both recipes show at one time and not individually

I am trying to show 2 different recipes depending on what recipe button I am clicking and unsure how to get that to stop and only show individual recipes.
\\First Card
<Card style={{ width: '18rem' }} className="Chicken">
<Card.Img variant="top" src={chicken} className="Fav_image" />
<Card.Body>
<Card.Title className="Fav_title">Chicken Paprakash</Card.Title>
<Card.Text className="Fav_text">
This is one of my favourite fall/winter recipes to make.
</Card.Text>
<Button variant="outlined" onClick={handleOpen} className="button">Recipe</Button>
</Card.Body> <Card>
\\Second Card
<Card style={{ width: '18rem' }} className="Fajita">
<Card.Img variant="top" src={fajita} className="Fav_image" />
<Card.Body>
<Card.Title className="Fav_title">Chicken Fajitas</Card.Title>
<Card.Text className="Fav_text">
Great for when you only have a few minutes to cook dinner.
</Card.Text>
<Button variant="outlined" onClick={handleOpen} className="button">Recipe</Button>
</Card.Body> <Card>
Here is the issue:
I tried multiple different fixes on Stack overflow but not luck
I assume that you're using the same useState for onClick={handleOpen} in your button? They're both opening due to the shared useState. The best way to solve this is to make another component where you render the <Card/>. This way each card component regulates its own state.
First step will be to create a state to store current opened food item:
const [currentOpen, setCurrentOpen] = React.useState(false);
Also change item handle open and handle close
const handleOpen = (item) => {
setOpen(true);
setCurrentOpen(item);
};
const handleClose = (item) => {
setOpen(false);
setCurrentOpen(item);
};
Now simply check for current item open while returning a card:
{currentOpen === "chicken1" && ()
{currentOpen === "chicken2" && ()
Here is whole code (components/Favourites/index.jsx):
import React from "react";
import Card from "react-bootstrap/Card";
import board from "../../assets/Favourites/0.jpg";
import chicken from "../../assets/Favourites/1.jpg";
import fajita from "../../assets/Favourites/2.jpg";
import Backdrop from "#mui/material/Backdrop";
import Box from "#mui/material/Box";
import Modal from "#mui/material/Modal";
import Fade from "#mui/material/Fade";
import Button from "react-bootstrap/Button";
import Row from "react-bootstrap/Row";
import Col from "react-bootstrap/Col";
import Typography from "#mui/material/Typography";
// import Nav from 'react-bootstrap/Nav';
const style = {
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
width: 400,
bgcolor: "background.paper",
border: "2px solid #000",
boxShadow: 24,
p: 4,
};
function Favourite() {
const [open, setOpen] = React.useState(false);
const [currentOpen, setCurrentOpen] = React.useState(false);
const handleOpen = (item) => {
setOpen(true);
setCurrentOpen(item);
};
const handleClose = (item) => {
setOpen(false);
setCurrentOpen(item);
};
return (
<>
<img
className="head-img"
src={board}
style={{ width: "100vw", height: "100vh" }}
alt="cutting board"
/>
<h1 className="Haleys_Favourites">Haley's Favourite Recipes</h1>
<Card style={{ width: "18rem" }} className="Chicken">
<Card.Img variant="top" src={chicken} className="Fav_image" />
<Card.Body>
<Card.Title className="Fav_title">Chicken Paprakash</Card.Title>
<Card.Text className="Fav_text">
This is one of my favourite fall/winter recipes to make.
</Card.Text>
<div>
<Button
variant="outlined"
onClick={() => handleOpen("chicken1")}
className="button"
>
Recipe
</Button>
{currentOpen === "chicken1" && (
<Modal
aria-labelledby="transition-modal-title"
aria-describedby="transition-modal-description"
open={open}
onClose={() => handleClose("chicken1")}
closeAfterTransition
BackdropComponent={Backdrop}
BackdropProps={{
timeout: 500,
}}
>
<Fade in={open}>
<Box sx={style}>
<Typography
id="transition-modal-title"
variant="h6"
component="h2"
className="chicken_title"
>
Chicken Paprakash
</Typography>
<Typography
id="transition-modal-title"
variant="subtitle1"
component="h2"
className="chicken_serving"
>
Serving: 4 people
</Typography>
<Row xs={1} md={2}>
<Col>
<Typography
id="transition-modal-description"
sx={{ mt: 2 }}
>
Ingredients:
<ol>
<li>4 chicken legs</li>
<li>oil</li>
<li>half an onion (chopped) </li>
<li>4 tablespoons of paprika</li>
<li>2 1/2 cups chicken broth</li>
<li>1 tub of sour cream</li>
<li>1 tablespoon of flour</li>
<li>salt</li>
<li>egg noodles</li>
</ol>
</Typography>
</Col>
<Col>
<Typography
id="transition-modal-description"
sx={{ mt: 2 }}
>
Instructions:
<ol>
<li>
Season chicken with salt and pepper then brown
chicken in oil.
</li>
<li>
As chicken is browning, combine sour cream and
flour.
</li>
<li>Put browned chicken in dutch oven.</li>
<li>Add more oil and cook onions until soft.</li>
<li>
Add paprika and stir completely. Add sour cream
and onion mix and stir completley and then add
chicken broth
</li>
<li>
Stir until all combined and cook for 10 minutes.
</li>
<li>
Pour sauce into dutch oven and cook at 350% for 45
minutes
</li>
<li>Serve with buttery egg noodles</li>
</ol>
</Typography>
<Typography
id="transition-modal-description"
sx={{ mt: 2 }}
className="exit"
variant="subtitle1"
>
Click outside of the box to exit!
</Typography>
</Col>
</Row>
</Box>
</Fade>
</Modal>
)}
</div>
</Card.Body>
</Card>
<Card style={{ width: "18rem" }} className="Fajita">
<Card.Img variant="top" src={fajita} className="Fav_image" />
<Card.Body>
<Card.Title className="Fav_title">Chicken Fajitas</Card.Title>
<Card.Text className="Fav_text">
Great for when you only have a few minutes to cook dinner.
</Card.Text>
<div>
<Button
variant="outlined"
onClick={() => handleOpen("chicken2")}
className="button"
>
Recipe
</Button>
{currentOpen === "chicken2" && (
<Modal
aria-labelledby="transition-modal-title"
aria-describedby="transition-modal-description"
open={open}
onClose={() => handleClose("chicken2")}
closeAfterTransition
BackdropComponent={Backdrop}
BackdropProps={{
timeout: 500,
}}
>
<Fade in={open}>
<Box sx={style}>
<Typography
id="transition-modal-title"
variant="h6"
component="h2"
className="Fav_title"
>
Chicken Fajitas
</Typography>
<Typography
id="transition-modal-titles"
variant="subtitle1"
component="h2"
className="Fav_serving"
>
Serving: 4 people
</Typography>
<Row>
<Col md={6}>
<Typography
id="transition-modal-description"
sx={{ mt: 2 }}
>
Ingredients:
<ol>
<li>3 chicken breast</li>
<li>oil</li>
<li>half an onion (sliced)</li>
<li>2 large peppers (sliced)</li>
<li>1-2 Old El Paso Fajita seasoning packets</li>
<li>Tortillas</li>
</ol>
</Typography>
</Col>
<Col md={6}>
<Typography
id="transition-modal-description"
sx={{ mt: 2 }}
>
Instructions:
<ol>
<li>Cook chicken in oil until cooked.</li>
<li>Add packets of seasoning.</li>
<li>Add onion and peppers.</li>
<li>
1/4-2/3 cups (depending how many packets used).
</li>
<li>Cook everything for 3-5 minutes</li>
<li>
Put in tortilla with all condaments you want.
</li>
</ol>
</Typography>
<Typography
id="transition-modal-description"
sx={{ mt: 2 }}
className="exit"
variant="subtitle1"
>
Click outside of the box to exit!
</Typography>
</Col>
</Row>
</Box>
</Fade>
</Modal>
)}
</div>
</Card.Body>
</Card>
{/* <Nav className="Fav_Home">
<Nav.Item>
<Nav.Link className="nav_home" href="/Home">Home</Nav.Link>
</Nav.Item>
</Nav> */}
</>
);
}
export default Favourite;

How to display only to items in row?

I Don't know how to display only two elements in row and keep last Column empty, spend almost 9h to find resolve
Red zone has to be empty, here is react component of the card
return (
<Row gutter={[24,24]}>
{
name.map((news)=>(
<Col xs={24} sm={12} lg={8} key={news.id}>
{/*<div className={"card"}>*/}
<Card hoverable className={"news-card"} style={{height: "250px"}}>
<a href={news.url} target={"_blank"} rel={"noreferrer"}>
<div className="news-image-container">
<Title className={"news-title"} level={4}>{news.name}</Title>
<img style={{maxWidth: '200px', maxHeight: '100px'}} src={news.image} alt={"news"}/>
</div>
<p>
{
news.description.length > 100 ? `${news.description.substring(0, 100)}...`
:news.description
}
</p>
<div className="provider-container">
<Text>{moment(news.datePublished).startOf('ss').fromNow()}</Text>
</div>
</a>
{/*</div>*/}
</Card>
</Col>
))
}
</Row>
);

react render using map on Grid

I'm trying to build a page that shows the weather in all the locations mentioned in a list.
I want to render a card for each location and sort the cards next to each other so every row will contain 5 location cards [][][][][],
currently, it renders only one under the other in a column:
how can I solve this?
(weather.favoritesWeather is a list that contains all the data which needs).
const FavoriteWeatherCards = weather.favoritesWeather.map(
(favoriteLocation) => (
<div>
<Row className="justify-content-md-center">
<Col md={3} >
<SmallConditionsCard data={favoriteLocation} />
</Col>
</Row>
</div>
)
);
return <div>
{FavoriteWeatherCards}
</div>;
};
code :
const SmallConditionsCard = ({data}) => {
const { location, weather } = data;
let history = useHistory();
const handleClick = () => {
history.push('/');
};
return (
<div>
<Card>
<CardHeader
sx={{ background: 'ghostwhite' }}
title={
<Typography align="center" variant="h5">
{location.name}
</Typography>
}
/>
<CardContent sx={{ textAlign: 'center' }}>
<WeatherIcon
number={weather[0].WeatherIcon}
xs={12}
sx={{ maxHeight: 200, maxWidth: 200 }}
/>
<Typography variant="h6">{weather[0].WeatherText}</Typography>
<Typography variant="p">
{formatTemp(weather[0].Temperature.Metric.Value, celcius)}
</Typography>
</CardContent>
<CardActions>
<Button size="small" onClick={handleClick}>Learn More </Button>
</CardActions>
</Card>
</div>
);
};
this is the result now:
If you are using react-bootstrap you need your container
const FavoriteWeatherCards = weather.favoritesWeather.map(
(favoriteLocation) => (
<Row className="justify-content-md-center">
<Col>
<SmallConditionsCard data={favoriteLocation} />
</Col>
</Row>
)
);
return <Container>
{FavoriteWeatherCards}
</Container>;
};
In case that you want to render something using material UI grid could be something like this
const FavoriteWeatherCards = weather.favoritesWeather.map(
(favoriteLocation) => (
<Grid item xs={3}>
<Item>
<SmallConditionsCard data={favoriteLocation} />
</item>
</Row>
</Grid>
)
);
return <Grid container spacing={2}>
{FavoriteWeatherCards}
</grid>;
};

React Dynamic append using map

I am new to react,
I am learning react, In this process I tried to create a for loop render using react. Were I am stuck in the following code
Below is my code
<Container>
<Row xs={3} md={4} lg={6}>
{[...Array(numberOfCards)].map((e, i) => {
return (
<Col className='mt-5' key={i+1}>
<Card >
{/* <Card.Img top width="100%" src="/images/companylogo.png" alt="Card image cap"/> */}
<Card.Body>
<Card.Title tag="h5">Card title</Card.Title>
<Card.Subtitle tag="h6" className="mb-2 text-muted">Card subtitle</Card.Subtitle>
<Card.Text>Some quick example text to build on the card title and make up the bulk of the
card's
content.</Card.Text>
<Button onClick={() =>addquantity({i+1},{email})}>Button</Button>
</Card.Body>
</Card>
</Col>
)
})}
</Row>
</Container>
here, In the Button Onclick event I am passing the "{i+1}"
Can you help me to understand what I am doing wrong here.
Thanks in advance
When you are defining the function in the onClick, the variables are in scope and shouldn't be inserted using {...} formats.
This should work (note that email should be defined somewhere):
<Container>
<Row xs={3} md={4} lg={6}>
{[...Array(numberOfCards)].map((e, i) => {
return (
<Col className='mt-5' key={i+1}>
<Card >
{/* <Card.Img top width="100%" src="/images/companylogo.png" alt="Card image cap"/> */}
<Card.Body>
<Card.Title tag="h5">Card title</Card.Title>
<Card.Subtitle tag="h6" className="mb-2 text-muted">Card subtitle</Card.Subtitle>
<Card.Text>Some quick example text to build on the card title and make up the bulk of the
card's
content.</Card.Text>
<Button onClick={() =>addquantity(i+1,email)}>Button</Button>
</Card.Body>
</Card>
</Col>
)
})}
</Row>
</Container>

React Router does not switch pages

I have a search bar and when I type in smth I see fetch movie list. then I click on the details button to see a description of according film, url changes but new component does not render. IDK why. Just when I click on according card item and as soon as I refresh the page it shows me the rendered Details page. Another issue that I receive props and param (imdbID) How to show all the details that were passed by props - {films}
function App() {
const [searchText, setSearchText] = useState('')
const [films, setFilms] = useState([])
const url = `http://www.omdbapi.com/?i=tt7286456&apikey=KEY&s=${searchText}`
const onTextChange = async (e) => {
setSearchText(e.target.value)
const res = await axios.get(url)
setFilms(res.data.Search)
console.log(films)
}
const history = createMemoryHistory()
return (
<>
<Router>
<Container>
<h1 className='mt-4'>MovieStore</h1>
<Row>
<input
style={{width: '90%', margin: '0 auto'}}
type='text'
placeholder='Try look for harry... or whatever film you like...'
name="searchText"
onChange={onTextChange}
value={searchText}
className='mt-4 mb-4'
/>
</Row>
<Row style={{color: "#000"}}>
{ films?.map(item => {
return (
<Col lg={3} md={3} sm={12} key={item.imdbID} >
<Card style={{height: 'calc(100% - 10px)' }}>
<Card.Img variant="top" src={item["Poster"]} style={{ objectFit: 'cover' }}/>
<Card.Body>
<Card.Title>{item["Title"]}</Card.Title>
<Card.Text>
{item["Year"]}
</Card.Text>
<Link to={`/film/${item.imdbID}`}><Button variant="primary">Details</Button></Link>
</Card.Body>
</Card>
</Col>
)
})}
</Row>
</Container>
<Route exact path='/film/:imdbID' render={(props) => <DetailPage films={films} {...props} />}/>
</Router>
</>
);
}
Here is my details page
const DetailsPage = ({films}) => {
const history = useHistory();
const location = useLocation();
const { id } = useParams()
console.log('props', id)
return (
<Container>
<Row>
<Col>
<Card style={{ width: '50%' }} className='mt-4'>
<Card.Body>
<Card.Title>Movie title: {id}</Card.Title>
<Card.Text>
</Card.Text>
<Button style={{background: '#CE0A03', border: 'none' }} variant="primary" onClick={() => history.goBack() }>Go on main page</Button>
</Card.Body>
</Card>
</Col>
</Row>
</Container>
)
}
If you want to render this component and hide other then use the switch in react-router.
<Router>
<Switch>
<Route exact path='/'>
<Container>
<h1 className='mt-4'>MovieStore</h1>
<Row>
<input
style={{width: '90%', margin: '0 auto'}}
type='text'
placeholder='Try look for harry... or whatever film you like...'
name="searchText"
onChange={onTextChange}
value={searchText}
className='mt-4 mb-4'
/>
</Row>
<Row style={{color: "#000"}}>
{ films?.map(item => {
return (
<Col lg={3} md={3} sm={12} key={item.imdbID} >
<Card style={{height: 'calc(100% - 10px)' }}>
<Card.Img variant="top" src={item["Poster"]} style={{ objectFit: 'cover' }}/>
<Card.Body>
<Card.Title>{item["Title"]}</Card.Title>
<Card.Text>
{item["Year"]}
</Card.Text>
<Link to={`/film/${item.imdbID}`}><Button variant="primary">Details</Button></Link>
</Card.Body>
</Card>
</Col>
)
})}
</Row>
</Container>
</Route>
<Route exact path='/film/:imdbID' render={(props) => <DetailPage films={films} {...props} />}/>
<Switch>
</Router>

Resources