简体   繁体   中英

Why is my CSS animation not applying to the correct element?

I'm trying to write a CSS animation that is activated when someone clicks on the element (as if to delete it). The elements are being rendered as part of a map, so it's a bit complicated. I haven't done this before, so sorry if it's dumb, this is what I tried to do.

WHAT'S CURRENTLY HAPPENING WITH THE CODE BELOW: When I click on something, the correct item just disappears (without any animation), but the next element in the array DOES receive the animation then reappears. But sometimes the animation doesn't show up at all. Why is the animation getting passed on the wrong element?

Here is the map where I'm rendering the different elements. Notice that I'm creating an id for each of sport.name.

this.state.sports.map((sport) => {    
      let imgPath = " ";
      if(/\s/g.test(sport.name.toLowerCase())){                                        
         imgPath = 'images/' + sport.name.replace(/\s/g, '').toLowerCase() + '.png'
         } else {
         imgPath = 'images/' + sport.name.toLowerCase() + '.png'
         }                   
         return(
            <div>
              <button className="sport-button" id={sport.name} onClick={() => this.deleteSport(sport.name)}>
                 <img src={imgPath} className="sport-image" /> 
                    {sport.name}
              </button>                         
            </div>
           )   
         })

Here is the deleteSport function that I have, which is currently the onClick handler. Inside it, I call another function called exitAnimation.

deleteSport = (name) => {
    for(let i of this.state.sports){
        if(i.name === name){
            let stateCopy = this.state.sports.filter(sport => sport.name !== i.name)            
            this.exitAnimation(name)
            console.log(name)
            this.setState({
                sports: stateCopy
            })            
        } 
    }
}

Here is the exitAnimation function that gets called...

exitAnimation = (name) => {
    document.getElementById(name.toString()).style.animation = "deleteAnimation 2s"
}

Aaaaaand here is the CSS animation that appears in my CSS stylesheet...

@keyframes deleteAnimation {
  from { opacity: 1; 
  }
   to { opacity: 0; 
  }        
}

You're deleting the item before the animation completes. See modified.

deleteSport = (name) => {
    for(let i of this.state.sports){
        if(i.name === name){
            const stateCopy = this.state.sports.filter(sport => sport.name !== i.name)            
            return this.exitAnimation(name, name => {
                this.setState({
                    sports: stateCopy
                })
            })         
        } 
    }
}

exitAnimation = (name, cb) => {
    document.getElementById(name.toString()).style.animation = "deleteAnimation 2s"
    // called when animation completes after 2s
    setTimeout(() => cb(name), 2000)
}

Note here we're just waiting 2s. Normally you can use an animation library that actually tells you when the animation is complete.

Update:

Try moving the stateCopy into the exitAnimation callback. There may be a race condition between the stateCopy and exitAnimation

deleteSport = (name) => {
    for(let sport of this.state.sports){
        if(sport.name === name){
            return this.exitAnimation(name, name => {
                const sports = this.state.sports.filter(sport => sport.name !== name)
                this.setState({
                    sports: sports
                })
            })         
        } 
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM