27

I want to play an animation on a react component every time it rerenders due to prop change:

react:

function Card({ cardText }) {
  return <div className="roll-out">{cardText}<div/>
}

So I did css:

@keyframes rollout {
  0% { transform: translateY(-100px); }
  100% { transform: none; }
}

.roll-out {
  animation: rollout 0.4s;
}

However, the animation only plays once, on the initial render. I want to play it every time <Card /> re-renders due to cardText change. How can I achieve it?

Quuxuu
  • 549
  • 1
  • 4
  • 10
  • Does this answer your question? [Can you force a React component to rerender without calling setState?](https://stackoverflow.com/questions/30626030/can-you-force-a-react-component-to-rerender-without-calling-setstate) – ezio4df Jul 31 '20 at 14:25

3 Answers3

56

Add a key like this:

function Card({ cardText }) {
  return <div key={cardText} className="roll-out">{cardText}<div/>
}

In your code, when the div re-renders, react only changes its inner text. Adding a key will make react think it's a different div when the key changes, so it'll unmount it and mount again.

ZYinMD
  • 3,602
  • 1
  • 23
  • 32
11

The trick here is to use a random key field on your card element. React's diffing algorithm considers elements with the same key as the same, so randomizing the key will make react consider each rerendered element as new, so will removed the old element from the DOM and add a brand new one

Here is a demo using @aXuser264 's code as a base.

class Card extends React.Component{
   onClick = ()=>this.forceUpdate();
   render(){
       return <div key={Math.random()} className="roll-out" onClick={this.onClick}> {
    this.props.cardText
     } </div>
  }
}

ReactDOM.render( (<Card cardText="Hey There" />) , document.getElementById('root'))
@keyframes rollout {
  0% {
    transform: translateY(-100px);
  }
  100% {
    transform: translateY(0);
  }
}

.roll-out {
  animation: .4s rollout;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>


<div id="root"></div>
Kai Salmon
  • 338
  • 1
  • 2
  • 9
1

To force element to re-render you can simply change its key prop which will trigger a render making react think its another element

Refer this answer: https://stackoverflow.com/a/35004739

function Card({
  cardText
}) {
  return <div className = "roll-out" > {
    cardText
  } </div>
}

ReactDOM.render( (<Card cardText="Hey There" />) , document.getElementById('root'))
@keyframes rollout {
  0% {
    transform: translateY(-100px);
  }
  100% {
    transform: translateY(0);
  }
}

.roll-out {
  animation: .4s rollout;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>


<div id="root"></div>
isherwood
  • 58,414
  • 16
  • 114
  • 157
ezio4df
  • 3,541
  • 6
  • 16
  • 31