Ogatron3000
Ogatron3000

Reputation: 21

Trigger Animate.css animation on each click in React

I'm having trouble in making animation trigger on each click - it only triggers once, when the page mounts.

The solution I found was to add a Math.random key to text I want to animate, but it doesn't work once I add new handler functions, because it triggers animation if any of the functions fire.

Also, I read that manipulating DOM in React is not a good practice.

I know that I can use synthetic event onAnimationEnd, but I want to trigger animation again on every click, without waiting for it to end.

I managed to get it to work in a bit of a hacky way, by adding one animation in setState of onClick function and then adding a different one in onAnimationStart.

What better way is there to solve this problem, ideally one that follow best practices?

Minimal workable example:

class App extends React.Component {
  state = {
    quotes: [{quote: "a", author: 1},
            {quote: "b", author: 2},
            {quote: "c", author: 3}],
    quote: {quote: "a", author: 1}
  }

  handleClick = () => {
    this.setState({
      quote: this.state.quotes[Math.floor(Math.random()*3)]
    });
  }
  
  render() {

    // assign random quote
    const quote = this.state.quotes.length ? (this.state.quote.quote) : ("Wait o");

    // assign author
    const author = this.state.quotes.length ? (this.state.quote.author) : ("");
   
    return(
      <div className="App">
        <p className="animated jackInTheBox">
          {quote}
        </p>
        <p className="animated jackInTheBox">
          {author}
        </p>
        <button id="new-quote" onClick={this.handleClick}>
          New Quote
        </button>
      </div>
     )
   }
}

ReactDOM.render(
  <App />,
  document.getElementById('root')
);
<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>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.7.2/animate.min.css">
</head>
<div id="root"></div>

Upvotes: 1

Views: 1580

Answers (1)

BENARD Patrick
BENARD Patrick

Reputation: 30975

class App extends React.Component {
  state = {
   classes:"animated jackInTheBox",
    quotes: [{quote: "a", author: 1},
            {quote: "b", author: 2},
            {quote: "c", author: 3}],
    quote: {quote: "a", author: 1}
  }

  handleClick = () => {
    this.setState({
      quote: this.state.quotes[Math.floor(Math.random()*3)],
      classes:"hidden"
    }, () => {
         setTimeout(() => this.setState({classes:"animated jackInTheBox"}),100)
      });
  }
  
  render() {

    // assign random quote
    const quote = this.state.quotes.length ? (this.state.quote.quote) : ("Wait o");

    // assign author
    const author = this.state.quotes.length ? (this.state.quote.author) : ("");
   
    return(
     
      <div className="App">
        <p className={this.state.classes}>
          {quote}
        </p>
        <p className={this.state.classes}>
          {author}
        </p>
        <button id="new-quote" onClick={this.handleClick}>
          New Quote
        </button>
      </div>
     )
   }
}

ReactDOM.render(
  <App />,
  document.getElementById('root')
);
<style>.hidden{opacity:0}</style>
<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>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.7.2/animate.min.css">
</head>
<div id="root"></div>

Upvotes: 1

Related Questions