I have a few images inside a directory in my React project, and in my component, I'm trying to import all of them and display it in a carousel using Bootstrap, this is the current code:
import Carousel from 'react-bootstrap/Carousel';
const slideImagesFolder = '../../img/main slider/';
function importAll(r) {
return r.keys().map(r);
}
const images = importAll(require.context('../../img/main slider/', false, /\.(png|jpe?g|svg)$/));
const Items = () => {
return images.map((e, i) => (
<Carousel.Item key={i}><img className="slide-image d-block" src={e} alt="" /></Carousel.Item>
))
}
function MyCarousel() {
return (
<Carousel fade interval={null}>
{/* <Carousel.Item>
<img
className="d-block"
src={images[0]}
alt="First slide"
/>
</Carousel.Item>
<Carousel.Item>
<img
className="d-block"
src={images[1]}
alt="Second slide"
/>
</Carousel.Item>
<Carousel.Item>
<img
className="d-block"
src={images[2]}
alt="Third slide"
/>
</Carousel.Item> */}
<Items/>
</Carousel>
);
}
export default MyCarousel;
I'm getting this error: "Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?"
I don't know why, but if I comment "<Items/>" line and uncomment the above lines, it works, I don't know why it works differently.
Issues
The Carousel component attaches refs to the children it's rendering, e.g. Carousel.Item normally, so it can take DOM measurements to handle layout/positioning of the UI.
There are two issues with this approach:
Images isn't forwarding any ref that is passed to it.
Images would need to receive a React ref for each Carousel.Item component it renders. This won't work since Image is the only child of Carousel and can only forward one ref.
Solution
Instead of creating another React component that renders the Carousel.Item components, just map them directly as children.
Example:
import Carousel from 'react-bootstrap/Carousel';
const slideImagesFolder = '../../img/main slider/';
function importAll(r) {
return r.keys().map(r);
}
const images = importAll(require.context('../../img/main slider/', false, /\.(png|jpe?g|svg)$/));
function MyCarousel() {
return (
<Carousel fade interval={null}>
{images.map((src, i) => (
<Carousel.Item key={i}>
<img className="slide-image d-block" src={src} alt="" />
</Carousel.Item>
))}
</Carousel>
);
}
export default MyCarousel;
Related
I am trying to use carousel in my react project to show reviews. I am using bootstrap carousel.
This is the carousel I am using
But I want to use like this
Every click on the button will slide in a item and one item will slide out.
I can do one at a time but not like this.
Here is my Code:
const ShowReviews = () => {
const { data: reviews, isLoading, refetch } = useQuery('reviews', () => fetch('https://.herokuapp.com/reviews',)
.then(res => res.json()))
refetch()
if (isLoading) {
return <Loading></Loading>
}
return (
<div>
<h1 className='text-center fw-bold my-5'>User Reviews ({reviews.length})</h1>
<div className='bg-dark bg-opacity-25 container-fluid'>
<Carousel>
{reviews.map(review => <Carousel.Item> <ReviewCard
key={review._id}
review={review}
></ReviewCard></Carousel.Item>)}
</Carousel>
</div>
</div>
);
};
export default ShowReviews;
Just put three review cards per Carousel.Item instead of one. Carousel.Item is just a wrapper for one carousel "page".
Carousel.Item is already styled in a certain way, that's why you need a container/wrapper right below it. In my example I used Stack with direction="horizontal":
<Carousel.Item style={{ height: 500 }}>
<Stack
direction="horizontal"
className="h-100 justify-content-center align-items-center"
gap={3}
>
<Card>...</Card>
<Card>...</Card>
<Card>...</Card>
</Stack>
</Carousel.Item>
https://codesandbox.io/s/relaxed-poitras-4w774i
I'm currently trying to product viewer using react-responsive-carousel and react-image-magnifiers.
It's based an example from https://github.com/AlexTechNoir/Next.js-e-commerce-online-store#nextjs-e-commerce-store.
The problem that I can't seem to work out is how to map the custom thumbnails to display properly. When I hard code the array it works fine, however when I try to dynamically map all of the thumbnails are rendered in the same array(The slide images and magnifier is working fine.)
I'm using Next js v10.0.4, Node v14.3.0
Here is my code:
ProductSlider.js
import { Carousel } from 'react-responsive-carousel'
import { SideBySideMagnifier } from 'react-image-magnifiers'
import { API_URL } from '../../utils/urls'
import {fromImageToUrl} from '../../utils/urls'
//Map Image Slider Function
export default function ProductSlider({ product }) {
const images = product.productImages
const renderCustomThumbs =() => {
const siteUrl = API_URL
const thumbList = images.map((product, index) =>
<picture key={index}>
<source data-srcSet={`${siteUrl}${product.url}`} type="image/jpg" />
<img
key={product._id}
src= {`${siteUrl}${product.url}`}
alt={product.alternativeText}
height="70"
/>
</picture>,
)
return [
[thumbList]
]
}
return (
<Carousel
showArrows={true}
showStatus={true}
showIndicators={false}
showThumbs={true}
autoPlay={false}
transitionTime={500}
swipeable={false}
emulateTouch={true}
renderThumbs={renderCustomThumbs}
>
{images.map((productImages, index) => (
<div key ={index}>
<SideBySideMagnifier
key={index}
imageSrc={fromImageToUrl(productImages)}
alwaysInPlace={true}
fillAvailableSpace={true}
/>
</div>
))}
)
</Carousel>
)
}
Here is the Hard Coded Version that works (I have tested it by inserting importing the data as well i.e.
<source data-srcSet={${siteUrl}${product[0].url}} type="image/jpg" /> and it works):
import { Carousel } from 'react-responsive-carousel'
import { SideBySideMagnifier } from 'react-image-magnifiers'
import "react-responsive-carousel/lib/styles/carousel.min.css";
export default function ProductSlider() {
const renderCustomThumbs = () => {
return [
<picture>
<source data-srcSet="/img/products/0/01.jpg" type="image/jpg" />
<img
key="01"
src="/img/products/0/01.jpg"
alt="First Thumbnail"
height="70"
/>
</picture>,
<picture>
<source data-srcSet="/img/products/0/02.jpg" type="image/jpg" />
<img
key="02"
src="/img/products/0/02.jpg"
alt="Second Thumbnail"
height="70"
/>
</picture>,
<picture>
<source data-srcSet="/img/products/0/03.jpg" type="image/jpg" />
<img
key="03"
src="/img/products/0/03.jpg"
alt="Third Thumbnail"
height="70"
/>
</picture>,
]
}
return (
<DivProductPage>
<Carousel
showArrows={false}
showStatus={true}
showIndicators={false}
showThumbs={true}
autoPlay={false}
transitionTime={500}
swipeable={false}
emulateTouch={true}
renderThumbs={renderCustomThumbs}
>
<div>
<SideBySideMagnifier
imageSrc="/img/products/0/01.jpg"
imageAlt="First Slide"
alwaysInPlace={true}
fillAvailableSpace={true}
/>
</div>
<div>
<SideBySideMagnifier
imageSrc="/img/products/0/02.jpg"
imageAlt="Second Slide"
alwaysInPlace={true}
fillAvailableSpace={true}
/>
</div>
<div>
<SideBySideMagnifier
imageSrc="/img/products/0/03.jpg"
imageAlt="Third Slide"
alwaysInPlace={true}
fillAvailableSpace={true}
/>
</div>
)
</Carousel>
</DivProductPage>
)
}
This is what the DOM returns from the developer console
[Returned Dom map not working as expected][1]
This is how it should look:
[Returned DOM from the hardcoded version][2]
Any Help you give me would be greatly appreciated, I'm stuck!
[1]: https://i.stack.imgur.com/JwKtn.png
[2]: https://i.stack.imgur.com/abEfA.png
In the return statement of the renderCustomThumbs function I was calling an array within an array, this resulted in the thumbs being rendered inside one array. The fix was to remove the arrays [] from the return statement.
The working function is shown here:
const renderCustomThumbs =() => {
const siteUrl = API_URL
const thumbList = images.map((product, index) =>
<picture key={index}>
<source data-srcSet={`${siteUrl}${product.url}`} type="image/jpg" />
<img
key={product._id}
src= {`${siteUrl}${product.url}`}
alt={product.alternativeText}
height="70"
/>
</picture>
)
return(thumbList)
I have been trying to use material-ui and iterate over it inside an array ( for creating ratings for some items like in e-commerce sites). The code isn't working. On my localhost server, it's not showing any stars at all. Before I made it dynamic, it was working all fine, then I added props to my functional component as per to make it dynamic. Everything else is working just fine except that it's not accepting my matrial-ui icon inside the array for me to iterate over. Moreover, the import statement says "it's value is never read although it's imported"
My code: Product.js:
import React from "react";
import "./Product.css";
import StarRateIcon from "#material-ui/icons/StarRate";
function Product({ id, title, image, price, rating }) {
return (
<div className="product">
<div className="product_info">
<p>{title}</p>
<p className="product_price">
<small>$</small>
<strong>{price}</strong>
</p>
<div className="product_rating">
{Array(rating)
.fill()
.map((_, i) => (
<p StarRateIcon className="star" />
))}
</div>
</div>
<img src={image} alt="" />
<button>Add to Basket</button>
</div>
);
}
export default Product;
My home.js file :
import React from "react";
import "./Home.css";
import Product from "./Product";
function Home() {
return (
<div classname="home">
<div className="home_container">
<img
className="home_image"
src="https://m.media-amazon.com/images/G/01/digital/video/sonata/US3P_JOKER_IMAGE_ID/be07783e-2738-4aaf-b90c-d0ec474d15ae._UR3000,600_SX1500_FMwebp_.jpg"
/>
<div className="home_row">
<Product
id="890778"
title="Description"
price={99.99}
image="https://m.media-amazon.com/images/I/71BGLa7IFtL._AC_UY218_.jpg"
rating={5}
/>
<Product />
</div>
</div>
</div>
);
}
export default Home;
Help Somebody! I can use emoji snippets but I really want this to work. I have imported StarRateIcon and used it. It isn't working.
Looks like you accidentally put a 'p' in front of your icon component name. You have <p StarRateIcon className="star" /> when it should be <StarRateIcon className="star" />
You're rendering a p tag with no content with an invalid attribute, StarRateIcon. It's the reason you're not seeing anything rendered. If you inspect the HTML, you'll most likely see the p tags. You may also see errors in the console about invalid attributes. Your code should look something like this:
Array(rating).fill().map(() => <StarRateIcon className="star" />)
I am using a function that maps every item in the props array to creating an image tag. I am trying to make every 3 images have a row div around them using bootstrap so they will fit the page correctly, but I cannot figure out how to do it. Any help would be appreciated. Here is the code:
import React, { Component } from 'react';
import "./Skills.css";
export default class Skills extends Component {
static defaultProps = {
images: [
"https://upload.wikimedia.org/wikipedia/commons/thumb/6/61/HTML5_logo_and_wordmark.svg/1200px-HTML5_logo_and_wordmark.svg.png",
"https://upload.wikimedia.org/wikipedia/commons/thumb/d/d5/CSS3_logo_and_wordmark.svg/1200px-CSS3_logo_and_wordmark.svg.png",
"https://upload.wikimedia.org/wikipedia/commons/6/6a/JavaScript-logo.png",
"https://p7.hiclipart.com/preview/306/37/167/node-js-javascript-web-application-express-js-computer-software-others.jpg",
"https://bs-uploads.toptal.io/blackfish-uploads/skill_page/content/logo_file/logo/5982/express_js-161052138fa79136c0474521906b55e2.png",
"https://webassets.mongodb.com/_com_assets/cms/mongodb_logo1-76twgcu2dm.png",
"https://www.pngfind.com/pngs/m/430-4309307_react-js-transparent-logo-hd-png-download.png",
"https://botw-pd.s3.amazonaws.com/styles/logo-thumbnail/s3/012015/bootstrap.png?itok=GTbtFeUj",
"https://sass-lang.com/assets/img/styleguide/color-1c4aab2b.png"
]
}
photo() {
return (
<div >
{this.props.images.map(image => (
<div className="col-md-4">
<img className="photo" src={image} />
</div>
))}
</div>
);
}
render() {
return (
<div id="skills-background" className="mt-5">
<div id="skills-heading" className="text-center">Skills I've Learned:</div>
<div className="container">
<div className="row">
{this.photo()}
</div>
</div>
</div>
)
}
}
CodeSandbox
I think, I found the issue,
<div> <-----This div is the issue
{this.props.images.map(image => (
<div className="col-md-4">
<img className="photo" src={image} />
</div>
))}
</div>
You have wrapped your col-md-4 with a div, and div has display: block style, so you are getting every image on separate row. Simply replace div with Fragments,
<> <-----Make it Fragment
{this.props.images.map(image => (
<div className="col-md-4">
<img className="photo" src={image} />
</div>
))}
</>
class App extends Component {
render(){
return (
<div className="App">
<MuiThemeProvider>
<div>
<GridList cellHeight={100}>
{this.props.data.map((cat) => (
<GridTile key={cat.photo} title={cat.title}>
{console.log(cat.photo)}
<img src={cat.photo} alt={cat.photo}/>
</GridTile>))}
<GridTile key="wiam.jpg" title="joijoiji">
<img src="wiam.jpg"/>
</GridTile>
</GridList>
</div>
</MuiThemeProvider>
</div>
);
}
}
"wiam.jpg" is a picture that I copied in my entire project folder, yet it doesn't display, but when I use an absolute link to a picture on a external website, I have no issue.
Where am I supposed to put the image on my server for it to appear ?
I had a similar problem. Images in material-ui components are distributed from the "public" directory. So if you have /public/images/wiam.jpg, src="images/wiam.jpg" should display the image correctly.