Home > Enterprise >  React hook useState updating all instances of component
React hook useState updating all instances of component

Time:03-02

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.

see https://usehooks.com/useEventListener/

  • Related