Reputation: 639
FINAL EDIT:
See working code below:
import React, { Component } from 'react';
var images = [
"https://www.royalcanin.com/~/media/Royal-Canin/Product-Categories/cat-adult-landing-hero.ashx",
"https://upload.wikimedia.org/wikipedia/commons/4/4d/Cat_March_2010-1.jpg"
]
class App extends Component {
constructor(props) {
super(props);
this.state = { imgPath: "url(" + images[1] + ")" };
}
componentDidMount() {
this.interval = setInterval(() => {
this.setState({ imgPath: "url(" + images[0] + ")" })
}, 1000);
}
componentWillUnmount() {
clearInterval(this.interval);
}
render() {
return (
<div className="App">
<div className='dynamicImage' style={{ backgroundImage: this.state.imgPath }} >
{console.log(this.state.imgPath)}
</div>
</div >
);
}
}
ORIGINAL THREAD:
I'm trying to use setInterval() to change the image dynamically every X seconds.
I just don't understand where setInterval is supposed to be placed within the code, or what its output is supposed to be.
My current code is:
import React, { Component } from 'react';
// Paths to my images
var images = [
"https://www.royalcanin.com/~/media/Royal-Canin/Product-Categories/cat-adult-landing-hero.ashx",
"https://upload.wikimedia.org/wikipedia/commons/4/4d/Cat_March_2010-1.jpg"
]
var imgPath = "url(" + images[1] + ")" // Set original value of path
function f1() {
imgPath = "url(" + images[0] + ")" // Change path when called ?
}
class App extends Component {
render() {
setInterval(f1, 500); // Run f1 every 500ms ?
return (
<div className="App">
<div className='dynamicImage' style={{ backgroundImage: imgPath }} > // Change background image to one specified by imgPath
</div>
</div >
);
}
}
export default App;
The current code outputs the first imgPath's URL, but fails to update it to the one specified within the function f1. To the best of my knowledge, the function f1 does appear to run, as removing it, or setting an undefined variable does return an error. I just can't get it to change imgPath.
Any ideas on what I'm doing wrong, or how I could improve my code?
Cheers
Edit: Commented code + removed unnecessary lines
Upvotes: 4
Views: 10037
Reputation: 7598
You need to use componentDidMount() React Lifecycle method to register your setInterval function.
Here is a working example
import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
images: [
"https://picsum.photos/200/300/?image=523",
"https://picsum.photos/200/300/?image=524"
],
selectedImage: "https://picsum.photos/200/300/?image=523"
};
}
componentDidMount() {
let intervalId = setInterval(() => {
this.setState(prevState => {
if (prevState.selectedImage === this.state.images[0]) {
return {
selectedImage: this.state.images[1]
};
} else {
return {
selectedImage: this.state.images[0]
};
}
});
}, 1000);
this.setState({
intervalId
});
}
componentWillUnmount() {
clearInterval(this.state.intervalId);
}
render() {
return (
<div className="App">
<img src={this.state.selectedImage} alt={"images"} />
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
You can change around the code and can find live demo here: https://codesandbox.io/s/0m12qmvprp
Upvotes: 1
Reputation: 1415
You can create an endless loop similar to this, you might want to use an array of image urls and write some logic for that. But as you can see I have an endless loop created for the function setImage()
:
constructor(props) {
super();
this.state = {
image1: props.imageUrls[0],
image2: props.imageUrls[1],
changeImage: true
};
this.setImage();
}
setImage() {
setTimeout(() => {
this.setState({ changeImage: !this.state.changeImage }, this.setImage());
}, 3000);
}
Upvotes: 1
Reputation: 358
I would move all your variables into your component and as Akash Salunkhe suggests, use componnentDidMount to setInterval. Don't forget to clear the interval when the component unmounts.
This answer will also work with using any number of images.
class App extends React.Component {
constructor(props) {
super(props);
const images = [
"https://www.royalcanin.com/~/media/Royal-Canin/Product-Categories/cat-adult-landing-hero.ashx",
"https://www.petfinder.com/wp-content/uploads/2013/09/cat-black-superstitious-fcs-cat-myths-162286659.jpg",
"https://upload.wikimedia.org/wikipedia/commons/4/4d/Cat_March_2010-1.jpg"
];
this.state = {
images,
currentImg: 0
}
}
componentDidMount() {
this.interval = setInterval(() => this.changeBackgroundImage(), 1000);
}
componentWillUnmount() {
if (this.interval) {
clearInterval(this.interval);
}
}
changeBackgroundImage() {
let newCurrentImg = 0;
const {images, currentImg} = this.state;
const noOfImages = images.length;
if (currentImg !== noOfImages - 1) {
newCurrentImg = currentImg + 1;
}
this.setState({currentImg: newCurrentImg});
}
render() {
const {images, currentImg} = this.state;
const urlString = `url('${images[currentImg]}')`;
return (
<div className="App">
<div className='dynamicImage' style={{backgroundImage: urlString}} >
</div>
</div >
);
}
}
Upvotes: 4
Reputation: 31
@Anurag is correct. You need to use setInterval
in componentDidMount
and ensure that you call this.setState
if you want the render method to rerender. This of course requires that you store the image path in this.state
Upvotes: 2
Reputation: 314
Put image path in state and in componentDidMount, use setInterval and inside it use setState to change image path.
Upvotes: 2
Reputation: 14413
You might want to use this.props
or this.state
to store the imgPath
, otherwise React doesn't know you have changed anything.
Upvotes: 2