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.
