11

I'm using the animate.css library with React and trying to set up a element (button) to pulse when hovered over. Tried to look through the docs and here but can't find a way to achieve this simple task. If anyone has achieved this or found a reference would greatly be appreciated.

class App extends Component {

   constructor(props) {
    super(props);

    this.handleHover = this.handleHover.bind(this);
  }

  handleHover(){
    this.setState({
        isHovered: !this.state.isHovered
    });
  }

  render() {
    const btnClass = this.state.isHovered ? "pulse animated" : "";

    return (
      <div>
        <button className={btnClass} onMouseEnter={this.state.handleHover} onMouseLeave={this.state.handleHover}>Test</button>
      </div>
    );
  }
}

export default App;
Brian Tompsett - 汤莱恩
  • 5,195
  • 62
  • 50
  • 120
Fernando B
  • 715
  • 2
  • 9
  • 23

2 Answers2

42

You can use the onMouseEnter and onMouseLeave events on the component and toggle the class accordingly.

constructor(){
    super();
    this.state = {
        isHovered: false
    };
    this.handleHover = this.handleHover.bind(this);
}
handleHover(){
    this.setState(prevState => ({
        isHovered: !prevState.isHovered
    }));
}
render(){
    const btnClass = this.state.isHovered ? "pulse animated" : "";
    return <button className={btnClass} onMouseEnter={this.handleHover} onMouseLeave={this.handleHover}></button>
}

Update 05/07/19: Hooks

import React, { useState } from 'react';

export default function Component () {
  const [hovered, setHovered] = useState(false);
  const toggleHover = () => setHovered(!hovered);
  return (
    <button 
      className={hovered ? 'pulse animated' : ''}
      onMouseEnter={toggleHover}
      onMouseLeave={toggleHover}
    >
    </button>
  )
}
Chase DeAnda
  • 13,160
  • 2
  • 26
  • 39
  • 1
    i got an error message when i hovered over `TypeError: Cannot read property 'setState' of null` **Specifically this line** `> 34 | this.setState({ ` – Fernando B Jun 16 '17 at 02:28
  • Yeah, you'll need to bind that function to your component, [check out the docs for more info](https://facebook.github.io/react/docs/handling-events.html). But basically you can either do `this.handleHover = this.handleHover.bind(this)` in the constructor, or change the props to `onMouseEnter={this.handleHover.bind(this)}` and `onMouseLeave={this.handleHover.bind(this)}`. – Chase DeAnda Jun 16 '17 at 14:43
  • I made an assumption on your project since you didn't post any example code. If you post the entire component it would be easier to help. – Chase DeAnda Jun 16 '17 at 14:44
  • sorry about that, i had added a state to my constructor but still doesn't seem to fix it, i added the code to my original question. – Fernando B Jun 16 '17 at 18:06
  • Okay thanks that helps a lot! So what your doing in the constructor is binding the function to the component, not adding it to state. So in your props, change it to `this.handleHover` instead of `this.state.handleHover`. – Chase DeAnda Jun 16 '17 at 18:46
  • And you need to add `this.state = { isHovered: false };` to the constructor to initialize your state. – Chase DeAnda Jun 16 '17 at 18:47
  • So what about the `prevState` variable? Where does that get defined or set? – tonejac Jan 30 '19 at 02:55
  • 1
    @tonejac It is passed in as an argument when providing a function as the first argument to `this.setState`: https://reactjs.org/docs/react-component.html#setstate – Chase DeAnda Jan 31 '19 at 03:23
  • This is a very great solution but can this be achieved via a stateless container? – Rishav May 07 '19 at 11:06
  • @ChaseDeAnda Your hook is solid. Thank you! I'm wondering if you have a suggestion for how to target only the element you're hovering? I obviously have a component that lives as several examples in a row and only want to target the nearest as opposed to activating all of them. – Alex Marple Jun 26 '19 at 16:49
  • @AlexMarple Sure, I would actually create a wrapper around each button that handles it. So in my example, `Component` becomes `Button` that you use for any button that you wish to apply the hover affect. That way, the hover affect will apply to each instance of `Button` separately. – Chase DeAnda Jun 26 '19 at 19:18
  • Better to call setHovered directly with a boolean value. There are cases where the state gets flipped the wrong way around. For example when you don't move the mouse but the element moves. This can happen when you delete an element or an element animates. – Webber Jul 16 '19 at 07:21
  • Voting down due to being incomplete. Good approach but overall this will leave people still confused. – JGallardo Oct 15 '19 at 20:17
  • @JGallardo What needs to be added for this to be a complete answer? Edit requests are accepted as well :) – Chase DeAnda Oct 16 '19 at 15:28
2

What about using the css :hover property? This worked way better for me by changing my hover class section in the css file to use :hover instead of react.

I tried using the above suggestions but react didn't seem fast enough to get it so the state would become wrong if the mouse moved slowly over the button.

ice1080
  • 111
  • 2
  • 8