I am working on a GatsbyJS project, using Contentful, and have created a template 'BlogPost'. Inside this template, I have imported a 'ResearchSlider' component. However, the images are not displaying at all.
I have passed down the image url data, as props, down to the researchSlider, which is then put inside the component state, and used in a function that passes each piece of image data into the 'Slide' child component, using a for loop. In 'Slide', the piece of image data is used as the value for backgroundImage in the styles of a div.
I would like to understand why they are not displaying and how I can fix this.
Here is the relevant code.
ResearchSlider component:
export default class ResearchSlider extends React.Component {
constructor(props) {
super(props);
this.state = {
images: [this.props.firstSlide,
this.props.secondSlide,
this.props.thirdSlide
],
translateValue: 0,
index: 0
}
this.renderSlides = this.renderSlides.bind(this);
this.handleClickPrevious = this.handleClickPrevious.bind(this);
this.handleClickNext = this.handleClickNext.bind(this);
this.slideWidth = this.slideWidth.bind(this);
}
renderSlides() {
const images = this.state.images;
let slides = []
for(let i = 0; i < images.length; i++)
slides.push(<Slide key={i} image={images[i]} />)
return slides
}
render() {
const { translateValue } = this.state
return(
<div className='slider'>
<div className="slider-wrapper"
style={{
transform: `translateX(${translateValue}px)`,
transition: 'transform ease-out 0.3s'
}}>
{ this.renderSlides() }
</div>
<ClickPrevious slideRight={this.handleClickPrevious}/>
<ClickNext slideLeft={this.handleClickNext}/>
</div>
);
}
'Slide' component:
import React from 'react';
const Slide = ({image}) => {
const styles = {
backgroundImage: `url("${image}")`,
backgroundSize: 'cover',
backgroundRepeat: 'no-repeat',
backgroundPosition: '50% 60%'
}
return <div className="slide" style={styles}></div>
}
export default Slide
Here is a screenshot of the inspection:
contentful assets URLs don't have the protocol attached to them they will in the following format //images.contentful.com/...... when setting this url to the src of an <img> tag the browser will assign the protocol automatically based on the protocol you app is using. But using the url in css you need to append explicitly the protocol to the url.
You Slide component should look like this.
const Slide = ({image}) => {
const styles = {
backgroundImage: `url("https:${image}")`,
backgroundSize: 'cover',
backgroundRepeat: 'no-repeat',
backgroundPosition: '50% 60%'
}
return <div className="slide" style={styles}></div>
}
export default Slide
Related
I am building a gallery where you click on the image and it will load in a separate component using props, this image is a URL, taken from a hard-coded array, where the src is loaded as a background image via CSS. My challenge is connecting the data to that component. I have tried connecting the data from parent to child with callbacks, but no luck. I think what I am trying to do is connect components sideways, and I don't want to use redux, as I am not familiar.
Note: I am aware you can just load the image in GalleryContainer.js using window.location.href = "props.src/", however, I want the image to load in the Image component that will act as a container to hold the image giving the user other options such as downloading the image, etc...
Note: I have tried importing the Image component in Gallery.js and rendering it like so: <Image src={props.src} id={props.id}/>, and I find the data connects just fine, but this does not help keep the component separate.
What I have already :
I have a route in app.js that allows me to go to the image route path just fine it’s loading in the url from props.src in the image component that is my challenge
UPDATE: SOLVED Click here to see the solution!
Here is the code:
GalleryList.js
import Gallery from "./Gallery";
import Header from "./UI/Header";
import Footer from "./UI/Footer";
import styles from "./Gallery.module.css";
const DUMMY_IMAGES = [
{
id: "img1",
src: "https://photos.smugmug.com/photos/i-vbN8fNz/1/X3/i-vbN8fNz-X3.jpg",
},
{
id: "img2",
src: "https://photos.smugmug.com/photos/i-fSkvQJS/1/X3/i-fSkvQJS-X3.jpg",
},
{
id: "img3",
src: "https://photos.smugmug.com/photos/i-pS99jb4/0/X3/i-pS99jb4-X3.jpg",
},
];
const GalleryList = () => {
const imagesList = DUMMY_IMAGES.map((image) => (
<Gallery id={image.id} key={image.id} src={image.src} />
));
return (
<>
<Header />
<ul className={styles.wrapper}>
<li className={styles.list}>{imagesList}</li>
</ul>
Home
<Footer />
</>
);
};
export default GalleryList;
Gallery.js
import GalleryConatiner from "./UI/GalleryContainer";
import styles from "./Gallery.module.css";
const Gallery = (props) => {
return (
<>
<div className={styles["gal-warp"]}>
<GalleryConatiner id={props.id} key={props.id} src={props.src} />
</div>
</>
);
};
export default Gallery;
GalleryContainer.js
import styles from "../Gallery.module.css";
const GalleryConatiner = (props) => {
const selectedImg = () => {
if (props.id) {
// window.location.href = `image/${props.src}`;
window.location.href = "image/"
}
};
return (
<ul>
<li className={styles["gallery-list"]}>
<div
onClick={selectedImg}
className={styles["div-gallery"]}
style={{
backgroundImage: `url(${props.src}`,
height: 250,
backgroundSize: "cover",
}}
></div>
</li>
</ul>
);
};
export default GalleryConatiner;
Image.js
import styles from "./Image.module.css";
const Image = (props) => {
return (
<section>
<h1 className={styles["h1-wrapper"]}>Image:{props.id}</h1>
<div className={styles.wrapper}>
<div
className={styles["image-container"]}
style={{
backgroundImage: `url(${props.src}`,
}}
></div>
</div>
</section>
);
};
export default Image;
You should be able to use the router Link to pass data via "state" on the to property.
From React Router's documentation:
<Link
to={{
pathname: "/images",
state: { imgUrl: props.src }
}}
/>
On my current project in React I need to have the possibility to change the background-style (image, width, height etc.) from a 'div' to nine different options.
I've tried it with following code:
const styleOptions = [
{
backgroundImage: "",
backgroundRepeat: "no-repeat",
backgroundPosition: "center",
//backgroundSize: "650px 800px",
backgroundSize: "cover"
},
{
backgroundImage: "url(/PicturesPattern/Picture1.png)",
backgroundRepeat: "no-repeat",
backgroundPosition: "center",
//backgroundSize: "650px 800px",
backgroundSize: "cover"
},
...//same code for nine Pictures, only diffrent size values
]
class Example extends React.Component {
state = {
...
...
//for selectionField
isDisabled: false,
backgroundStyle: styleOptions[0]
};
...
...
...
onSelectChange = (event) => {
this.setState({
...
currentStyle: styleOptions[event.value + 1]
});
};
render() {
return (
<>
//div for selectionField
<div className="forBackground" style{this.backgroundStyle}>
...
...
//other code
...
...
</>
)
}
}
But on any change from my selection field, there isnt happening anything to the background of the specific div.
When I put "styleOptions[x]" for x every index possible, I get the specific background image and other style options.
What am I doing wrong?
Hope someone can help me :)
Well, in the onSelectChange function and in the event.value + 1 part you are adding two different types of variables (string and integer). As a result the background styles of div would not change properly. First, you should write this function as below
onSelectChange = (event) => {
this.setState({
backgroundStyle: styleOptions[parseInt(event.target.value) + 1],
});
};
Then, style{this.backgroundStyle} should be changed to style={this.state.backgroundStyle}. I also added the height attributes and assigned a backgroundColor to make the div and changes more visible
But there were also other minor modifications. So, check the sandbox of the corrected version of your code.
I'm looking to display a different image for every link I hover over. When I hover over each link, both images display on top of each other. I feel as if my issue stems from the conditional, which will show any image I place within it and not just one specific image.
I'm wondering if there's a better approach. Perhaps holding the images within the state?
My code:
class PhotoIndex extends Component {
state = {
hover: false
}
mouseOver = () => {
this.setState({ hover: true })
}
mouseOut = () => {
this.setState({ hover: false })
}
render() {
return (
<Wrapper>
<IndexWrapper>
<li>
<StyledLink
onMouseOver={this.mouseOver}
onMouseOut={this.mouseOut}
to="/checkered-flag/">Checkered Flag
{this.state.hover
?
<Fade >
<div style={{ position: 'relative' }}>
<img
style={{ position: 'absolute', top: '-200px', left: '100%' }}
src={car14}
alt="red car parked in a parkin lot"
/>
</div>
</Fade>
: null}
</StyledLink>
</li>
<li>
<StyledLink
onMouseOver={this.mouseOver}
onMouseOut={this.mouseOut}>
Birds Nest
{this.state.hover
?
<Fade >
<div style={{ position: 'relative' }}>
<img
style={{ position: 'absolute', top: '-200px', left: '100%' }}
src={car15}
alt="blue car parked in a grassy field"
/>
</div>
</Fade>
: null}
</StyledLink>
</li>
<li>
<StyledLink>The Grand Turret</StyledLink>
</li>
<li>
<StyledLink>Simulation Theory</StyledLink>
</li>
</IndexWrapper>
</Wrapper>
)
}
}
I will try to simplify the code to explain the solution.
If you wish to go with this solution the images should be numbered in order with a set structure. For example car0.jpg ,car1.jpg, car2.jpg .....
ImageGetter.js
import car1 from './cars/car1.jpg';
import car2 from './cars/car2.jpg';
export default {
car1,car2
}
In the above code I am importing the images and exporting them so they can be consumed by any component which uses the ImageGetter object.
PhotoIndex.js
import ImageGetter from './ImageGetter';
class PhotoIndex extends Component {
constructor() {
super();
this.state = {
carImgNum: '0',
hover: false
}
}
mouseOver = () => {
const max = 5; //Max number of images
const newcarImgNum = Math.floor(Math.random() * Math.floor(max));
this.setState({ hover: true, carImgNum: newcarImgNum });
}
render() {
const { carImgNum } = this.state;
return (
<div onMouseOver={this.mouseOver}>
<img src={ImageGetter[`car${carImgNum}`]} alt="" />
</div>
)
}
}
export default PhotoIndex;
You will have to create a default state for the number of the image which will be displayed. Over here the default image displayed will be car0.jpg.
In mouseOver function you will have to define how many images are available. (You can make the number of images dynamic with some other function too.).
It then creates a random number from 0 to the max number you specified and sets the value to the carImgNum state.
Over in the render method I am de structuring the state to get the carImgNum value.
I then pass the ImageGetter into src of the image tag and dynamically target the image i need to pass using templatestrings.
I'm using React with Redux, and I have the following situation. In my component I have a div that holds and image, and the component is also receiving a property from my Redux state which is called showIcon. So, if showIcon is not null, I want the image to be displayed for 5 seconds, and once the 5 seconds passes, I want it to disappear and set the showIcon value to null by dispatching an action that I have like updateShowIcon(null);. How can I do this properly in React, and how can I use CSS to show and animate the icon as I want?
import React, { Component } from 'react';
class MyComp extends Component {
render() {
return (
<div style={styles.mainDiv}>
<div style={styles.childDiv}>
{
this.props.showIcon &&
<div style={styles.iconStlyes}>
<img src={process.env.PUBLIC_URL + '/icons/myicon.png'}/>
</div>
}
// partially removed for brevity, some other component
</div>
</div>
);
}
}
const styles = {
iconStlyes: {
position: 'absolute',
zIndex: 10,
},
mainDiv: {
overflow: 'auto',
margin: 'auto',
height: 'calc(100vh - 64px)',
padding: 0,
},
childDiv: {
height: 'calc(100vh - 64px)',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
},
};
export default MyComp;
Whenever I detect a change in componentWillReceiveProps I would create a timer and dispatch the action. Remember to clear the timeout on componentWillUnmount.
The idea is based on you showing and hiding the icon with css and not with react conditional rendering, so once you need to show the icon you add the class show or remove it once you don't need to show it.
It would probably look like this:
componentWillReceiveProps(nextProps){
if (nextProps.showIcon && nextProps.showIcon !== this.props.showIcon){
this.timer = setTimeout(() => {nextProps.updateShowIcon(null)}, 5000);
}
}
componentWillUnmount(){
clearTimeout(this.timer);
}
render() {
const {showIcon} = this.props;
return (
<div style={styles.mainDiv}>
<div style={styles.childDiv}>
<div style={styles.iconStlyes} className={`${showIcon ? 'show':''} icon-container`}>
<img src={process.env.PUBLIC_URL + '/icons/myicon.png'}/>
</div>
</div>
</div>
);
}
and your css for a simple fade animation:
.icon-container{
opacity: 0;
transition: opacity: 500ms ease-in;
}
.icon-container.show{
opacity: 1;
}
If it is important for you to use the store state then you can manage the showIcon property via componentWillReceiveProps(nextProps) and do something like:
componentWillReceiveProps(nextProps){
if(!this.props.showIcon && nextProps.showIcon){
setTimeout(()=>dispatch(updateShowIcon(null)),5*1000);
}
//manage clear timeout if necessary
}
But for the animation part its better to use the showIcon property as a class and not for adding/removing it from the DOM, like:
<div style={styles.iconStlyes} className={this.props.showIcon?'show':'hide'}>
<img src={process.env.PUBLIC_URL + '/icons/myicon.png'}/>
</div>
and the styles should manage it:
iconStyles: {
position: 'absolute',
zIndex: 10;
transition: //effects of specified or all attributes
&.show{
visibility: visible;//display:block
}
&.hide{
visibility: hidden;//display:none
}
}
One part of my application is an image gallery. When the user clicks on an image, I want to put an opaque layer over the image to visualize that it is selected.
When I display the layer, and I click on the image to deselect it, naturally I'm actually clicking on the layer.
Here's the relevant ReactJS code to show what I mean:
{images.map((i, idx) => (
<div key={"cont"+idx} className="container">
<img src={i.images} ref={"img"+idx} />
<div onClick={this.handleIconDeselect} id={"div_"+idx}></div>
</div>
)
)}
I tried to give the img a unique ref (as shown above), but I'm having trouble selecting the correct img.
This is how I try to select the correct image:
handleIconDeselect = (event) => {
var imgref = "icon"+event.target.id.split("_").pop();
this.refs.imgref.click();
}
However, I get the following error message:
TypeError: Cannot read property 'click' of undefined
How can I select the correct image while using unique refs?
Alternatively, if the way I'm trying to achieve this is bad practice (I know you should only use refs when absolutely necessary), what is a better way to do it?
Try use state as here: https://codesandbox.io/s/m4276x643y
Maybe that is not the best way but it give you an rough idea.
import React, { Component } from "react";
import { render } from "react-dom";
import Hello from "./Hello";
const coverStyle = {
position: "fixed",
top: 0,
left: 0,
zIndex: -1,
opacity: 0,
width: "100%",
height: "100%",
background: "#000"
};
const coverStyleShow = {
...coverStyle,
zIndex: 1,
opacity: 1
};
const imgShow = {
zIndex: 10,
position: "relative"
};
const images = [
"https://dummyimage.com/100.png/f10/fff",
"https://dummyimage.com/100.png/f20/fff",
"https://dummyimage.com/100.png/f30/fff",
"https://dummyimage.com/100.png/f40/fff",
"https://dummyimage.com/100.png/f50/fff",
"https://dummyimage.com/100.png/f60/fff",
"https://dummyimage.com/100.png/f70/fff"
];
class App extends Component {
constructor(props) {
super(props);
this.state = {
cover: coverStyle,
img: imgShow,
imgId: null,
imgShow: false
};
}
handleImageClick = (target, idx) => {
// you can do something with this "target"...
this.setState({
cover: coverStyle,
coverShow: coverStyleShow,
imgId: idx,
imgShow: !this.state.imgShow
});
};
render() {
return (
<div>
<Hello name="CodeSandbox" />
<h2>Start editing to see some magic happen {"\u2728"}</h2>
<div>
{images.map((img, idx) => (
<img
key={img}
src={img}
style={idx === this.state.imgId ? this.state.img : null}
onClick={event => this.handleImageClick(event.target, idx)}
alt="dummy img"
/>
))}
</div>
<span
style={this.state.imgShow ? this.state.coverShow : this.state.cover}
/>
</div>
);
}
}
render(<App />, document.getElementById("root"));