I'm trying to create a card with a background image changing on mouse movement on it, using a useState. The code works fine, but if I create multiple instances of the card component when I move on a card, it'll cause the state update of all the instances of the card. How can I prevent my code from doing this?
The instantiation of the components:
<div className="aboutCardContainer">
{Object.entries(members).map(([key,value])=>{
return(<AboutCard key={key} id={key} {...value}/>)
})}
</div>
The component code:
import React, { useState } from "react";
import { Link } from "react-router-dom";
import $ from 'jquery';
const AboutCard = ({id, name, role, description, link, image, colored_image}) => {
const [backImg, setBackImg] = useState(0);
var active = 0;
var currentProfile = 0;
var unitPhoto= 0;
$(document).on('mousemove', '.profileImage', function(event){
var id = $(this).parent().parent().attr('id');
currentProfile=id;
if(id !== currentProfile){
return;
}
unitPhoto = 100/(image.length-1);
var offset = $(this).offset();
let x = event.pageX- offset.left;
let w =$( this ).width();
x = (x*100)/w;
let index = Math.floor(x/unitPhoto);
if(index === 0){
setBackImg(colored_image);
return;
}
if(index >= image.length){
index = image.length-1;
}
if(index <0){
return;
}
if(index !== active || index != colored_image){
setBackImg(index);
active=index;
}
});
$(document).on('touchmove', '.profileImage', function(event){
var id = $(this).parent().parent().attr('id');
if(id !== currentProfile){
currentProfile=id;
unitPhoto = 100/(image.length-1);
}
var offset = $(this).offset();
let x = event.touches[0].pageX - offset.left;
let w =$( this ).width();
x = (x*100)/w;
let index = Math.floor(x/unitPhoto);
if(index === 0){
setBackImg(colored_image);
}
if(index >= image.length){
index = image.length-1;
}
if(index <0){
return;
}
if(index !== active || index != colored_image){
setBackImg(index);
active=index;
}
});
return (
<div className="aboutDiv" id={id}>
<Link to={`${link}`}>
<div id={'image-' id} style={{
background: `url(${image[backImg]})`,
}} className="profileImage">
</div>
</Link>
<h3 className="profileName">{name}</h3>
<p className="profileRole">{role}</p>
</div>
);
};
export default AboutCard;
CodePudding user response:
It's because your jQuery event listeners are listening to document wide notifications. Ie All AboutCard mousemove listeners will run every time there is a mousemove event on an element with the class profileImage (which is every instance of your component).
I would avoid mixing jQuery and React like this - they each manipulate the dom in a different way. Create a local ref (useRef) within your component and attach an eventListener the react way, which just listens to events on the local ref.