I'm using React to Create an img
element that changes its src
attribute after specific time with setInterval
function based on an array that contains many images.
so the thing is i want to make an animation whenever the src
attribute changes, i was thinking of using React.useEffect()
hook to watch the src
changes and add some animation but i couldn't go further logically.
my code :
import Canada from "../images/Canada.jpg"
import Tokyo from "../images/Tokyo.jpg"
import NewYork from "../images/NewYork.jpg"
import southKorea from "../images/southKorea.jpg"
function AboutMe() {
const imgArray = [NewYork, Tokyo, Canada, southKorea]
let i = 0;
const maxImgArray = imgArray.length -1 ;
const swap = function() {
let image = imgArray[i];
i = (i === maxImgArray) ? 0 : i;
const attr = document.getElementById("moving-image");
attr.src=image;
}
setInterval(swap, 5000)
return (
<section className="About-me">
<h1>About me</h1>
<div className="container">
<div className="cities-images">
<img
src={Tokyo}
alt="NewYork" id="moving-image"></img>
<label >
<input type="checkbox"/>
<span ></span>
</label>
</div>
<div className="info">
</div>
</div>
</section>
)
}
CodePudding user response:
By using useState
hook in react, we can re-render the component with updated value. So for src
change, we can use useState to update the current src of the image.
By using useEffect
hook we can do anything once src
state change like set different animations.
Component State
const [image, setImage] = useState(Usa);
const [imageIndex, setImageIndex] = useState(0);
const imgArray = [Usa, Japan, Canada, SouthKorea];
useEffect
useEffect(() => {
let interval = null;
if (i !== maxImgArray) {
interval = setInterval(() => {
let image = imgArray[imageIndex];
const attr = document.getElementById("moving-image");
attr.src = image;
// update the img index to state
setImageIndex((imageIndex) =>
imageIndex === maxImgArray ? 0 : imageIndex 1
);
// update the src in state.
setImage(attr.src);
}, 3000);
}
// When our code runs and reruns for every render, useEffect also cleans up after itself using the cleanup function.
// Here we clear the interval to remove the effects that could happen with state change while interval.
return () => clearInterval(interval);
}, [image, imageIndex]); // when image, imageIndex gets change, useEffect will be triggered.
Component here I used framer-motion for animation.
<section className="Country-flag">
<h1>Country Flag</h1>
<div className="container">
<motion.div
key={image}
animate={{ x: 100, opacity: 1 }}
transition={{
delay: 1,
x: { type: "spring", stiffness: 100 },
default: { duration: 2 }
}}
>
{/* when state {image} value change, this component will re-render with new src */}
<img alt="NewYork" src={image} id="moving-image"></img>
</motion.div>
<div className="info"></div>
</div>
</section>
Check this sample sandbox for produced code.
If you want different animations for each img, then add another state variable for animation and change the value inside the useEffect for each image state.