React Bootstrap Cards and CardDeck Components - responsive layout - reactjs

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

Related

Grid cards on bootstrap for React is displaying the same element four times, instead of different elements 4 times

I'm currently trying to apply tome styling to one lab, using the cards from bootstrap.
I want it to display 4 elements horizontal per row, it is working BUT, is showing the same element 4 times and the idea is to show 4 different elements per row. Can somebody please help me?
Here is the code:
import React from "react";
import Navbars from "./Navbars";
import Card from "react-bootstrap/Card";
import Col from 'react-bootstrap/Col';
import Row from 'react-bootstrap/Row';
const Beers = ({ beers }) => {
return (
<div>
<Navbars />
{beers.map((beer) => {
return (
<div>
<Row xs={1} md={4} className="g-4">
{Array.from({ length: 4 }).map((_, idx) => (
<Col>
<Card>
<Card.Img variant="top" src={beer.image_url} alt="" />
<Card.Body>
<Card.Title>{beer.name}</Card.Title>
<Card.Text>
{beer.tagline}
</Card.Text>
</Card.Body>
</Card>
</Col>
))}
</Row>
</div>
);
})}
</div>
);
};
export default Beers;
I tried switching the {beers.map((beer) to .map((_, idx) but it didn't work, I also try leaving only one return by putting {beers.map((beer) before the first return but it also didn't work.

react-bootstrap Carousel breaks when changing content during transition

video of issue:
When the carousel is transitioning from one slide to another, if another entry from a dataset is choosen, before the slide finishes its transition, the new images are rendered, but controls/timer are broken, so the carousel is not slidable any more (manually or automatically).
activeFish is a useState object with some fish data that gets changed with setActiveFish(newActiveFishDataObject) when a list item is clicked
Anyone have ideas for a solution?
<Carousel>
{activeFish['Image Gallery'].map((imageData, i) => (
<Carousel.Item key={imageData.title + i}>
<div className="image-container">
<img
className="d-block w-100"
src={imageData.src}
alt={imageData.alt}
/>
</div>
<Carousel.Caption>
<p>{imageData.title}</p>
</Carousel.Caption>
</Carousel.Item>
))}
</Carousel>
Replicate-
https://codesandbox.io/s/frosty-night-yckxro (thanks to #IgorGonak)
onload, immediately click the down arrow on the dropdown to expose options, mouse over option b, wait for transition to happen, click b rite in the middle of the transition. observe controls wont work for the 'b' dataset
I've created a dummy data with three entries and three images each entry. Then I built a select to select one and the carousel like yours - it is working on my side: When I choose another entry, the images in carousel are adjusted. The transition is working and is performed after each defined timeout:
https://codesandbox.io/s/frosty-night-yckxro
import React from "react";
import { Carousel, Form, Stack } from "react-bootstrap";
import data from "./fishData";
export default function App() {
const [activeFish, setActiveFish] = React.useState(data[0]);
const onSelect = (event) => {
const choosenFishName = event.target.value;
const choosenFish = data.find((fish) => fish.name === choosenFishName);
setActiveFish(choosenFish);
};
return (
<Stack className="m-3">
<Form.Group id="fish-select" className="mb-3" style={{ width: "18rem" }}>
<Form.Select value={activeFish.name} onChange={onSelect}>
{data.map((entry) => (
<option key={entry.name} value={entry.name}>
{entry.name}
</option>
))}
</Form.Select>
</Form.Group>
<p>Choosen fish is: {activeFish.name}</p>
<Carousel style={{ height: 200, width: 300 }}>
{activeFish["Image Gallery"].map((img) => {
return (
<Carousel.Item key={img.title}>
<img className="d-block w-100" src={img.src} alt={img.alt} />
<Carousel.Caption>{img.title}</Carousel.Caption>
</Carousel.Item>
);
})}
</Carousel>
</Stack>
);
}
Edit:
According to https://github.com/react-bootstrap/react-bootstrap/issues/6352 the problem here is that there is a state called "isSliding" in Carousel component. If it's true, the controls are deactivated. When we change children while sliding "isSliding" is true, but it's not set to false in the end, because the appropriate callback is never fired.
The solution is to reset the component by adding unique key to it:
<Carousel
key={activeFish.name}
interval={2000}
style={{ height: 200, width: 300 }}
>
{activeFish["Image Gallery"].map((img) => {
return (
<Carousel.Item key={img.title}>
<img className="d-block w-100" src={img.src} alt={img.alt} />
<Carousel.Caption>{img.title}</Carousel.Caption>
</Carousel.Item>
);
})}
</Carousel>

How do I use Bootstrap grid with components in react?

I want to get at least 2 cards on the same row but since the data is getting mapped one by one, I have no idea how to do so. I am using a custom component named 'Content' and returning data here
import React from "react";
import { Card, CardGroup, Col, Row } from "react-bootstrap";
import { ListGroup, ListGroupItem } from "react-bootstrap";
const Content=({name, image, type, vegan, cuisines})=>{
return(
<div>
<CardGroup>
<Col xs={12} sm={6} md={4} lg={4}>
<Card>
<Card.Img variant="top" src={image} />
<Card.Body>
<Card.Title>{name}</Card.Title>
<Card.Text>
<ListGroup>
<ListGroupItem>Type: {type}</ListGroupItem>
<ListGroupItem>Vegan: {vegan}</ListGroupItem>
<ListGroupItem>Cuisines: {cuisines.cuisines.join(", ")}</ListGroupItem>
</ListGroup>
</Card.Text>
</Card.Body>
</Card>
</Col>
</CardGroup>
</div>
)
}
export default Content
I believe you aren't using the Row component to wrap your columns.
Try replacing <CardGroup> with <Row> as shown in this section of the docs.

How can I render <Card.Text> as <div> element and not as <p>?

For <Card.Body> there seems to be a parameter named as which is of type elementType and defaults to <div>.
https://react-bootstrap.github.io/components/cards/#card-body-props
Now <Card.Text> defaults to <p> which results in warnings on my website as I have nested <div> elements inside <Card.Text>
Warning: validateDOMNesting(...): cannot appear as a descendant of <p>
So basically two questions:
How can I change/set the elementtype on Card.Body? The following attempts did not get reflected in the produced html (checked with Chrome DevTools): <Card.Body as="p">...</Card.Body> nor did this <Card.Body as="<p>">...</Card.Body>
How can I change the elementtype on <Card.Text>?
This is what my component looks like
import React from "react"
import { Link } from "gatsby"
import Img from "gatsby-image"
import Card from "react-bootstrap/Card"
import Tags from "./tags"
import TimeToRead from "./time-to-read"
const Post = ({ title, slug, date, body, fluid, tags, timeToRead }) => {
return (
<Card className="mb-3 shadow-lg" bg="concrete" id="hoverable">
<Link to={slug}>
<Img
className="card-image-top"
style={{ maxHeight: "150px" }}
fluid={fluid}
></Img>
<Card.ImgOverlay
style={{
pointerEvents: "none",
}}
>
<Tags tags={tags} />
</Card.ImgOverlay>
</Link>
<Card.Body>
<Card.Title>{title}</Card.Title>
<Card.Subtitle>
<div className="d-flex justify-content-between">
<span className="text-info">{date}</span>
<TimeToRead minutes={timeToRead} />
</div>
</Card.Subtitle>
<hr />
<Card.Text as="div">{body}</Card.Text>
<Link
to={slug}
className="btn btn-outline-primary float-right text-uppercase"
>
Read more
</Link>
</Card.Body>
</Card>
)
}
export default Post
I had the same problem, essentially. I used an unordered list inside the text for the <Card.Body> and the console displayed the following warning:
validateDOMNesting(...): <ul> cannot appear as descendent of <p>.
Wrapping the list content inside a <div> just added to the warning list. As suggested above, I amended the <Card.Text> tag, but as follows:
<Card.Text as="div">
The warning disappeared and the text renders. Note, you have to adjust the styling, depending on how the styling cascade is configured.

Bootstrap card in react

I'm suffering from implementing bootstrap in react. I set up bootstrap4 at the beginning but I got a bad layout then used react-bootstrap and I get the same issue. Th card body,title and button appear on the image itselfenter image description here
import React from 'react';
import { Card, Button } from 'react-bootstrap';
const WorkCard = () => {
return (
<div>
<Card style={{ width: '18rem' }} >
<Card.Img variant="top" src="holder.js/100px180" />
<Card.Body>
<Card.Title>Card Title</Card.Title>
<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 variant="primary">Go somewhere</Button>
</Card.Body>
</Card >
</div>
)
}
export default WorkCard;
Using sass was overriding the bootstrap so I fixed that.

Resources