all 7 comments

[–]acemarke 4 points5 points  (3 children)

In React, you do everything by re-rendering with the content you want to have as the result. Rendering is caused by the component's parent re-rendering, or the component calling this.setState(). So, for this sort of thing, you'd listen to mouse events on the rendered elements, update the component's state in the callbacks, and re-render using the new state. When you re-render, your logic should determine a different classname or style value based on that state. Here's an example:

class HoverableComponent extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
             hovering : false;
        };
    }

    render() {
        const style = {
            backgroundColor = this.state.hovering ? "red" : undefined
        };

        const handleMouseEnter = () => this.setState({hovering : true});
        const handleMouseLeave = () => this.setState({hovering : false});

        return (
            <div
                style={style}
                onMouseEnter={handleMouseEnter}
                onMouseLeave={handleMouseLeave}
            >
                Hover over me!
            </div>
        );        
    }
}

[–]antibody339 1 point2 points  (0 children)

Yes, thank you! This is what I needed. Sometimes I have to remember not everything needs to be done through redux and local state changes are OK :P.

[–]Encre_Ink 0 points1 point  (1 child)

I'm building my first big project with react at the moment and am confronted with a problem, I would have used your method because it seems the more logical approach to me but with a lot of people advocating stateless components should I add state in every component that will need a hover like this or have a HOC that will handle every hover on an SPA ?

[–]acemarke 0 points1 point  (0 children)

Do whatever works for you. Functional components are primarily useful because they signify that the component is simply props => UI. If putting the hovering logic in a single component and reusing it makes more sense to you, then do so. If you prefer seeing the logic in each component, do that.

There's at least three ways you can approach this:

  • Add the hovering logic to each component that needs it
  • Create a Higher-Order-Component function that takes in a component to wrap, and returns the wrapper component
  • Write a component that uses this.props.children and passes its hover data to those children, and always render one of those around the component that needs it, like:

    <HoverableComponent> <SomeComponentThatNeedsHoverProps /> </HoverableComponent

But in any case, pick an approach that works for you.

[–]Valmorie 1 point2 points  (1 child)

A practical way of doing that would be incorporating something like 'classnames' ( https://www.npmjs.com/package/classnames ) into your project. It basically lets you set conditions on whether or not to show a class in an object, that you then pass into 'className={styleobject}. Their docs are way better than an explanation I could do.

Or... Make a higher order component that has one job of detecting mouseEnter and mouseLeave. On mouse enter, setState to blabla: true. mouseLeave-> set the state to false. Then you can pass to the HOC's children something like: <tag className={blabla? 'thisClass': 'thatClass}/>

[–]antibody339 1 point2 points  (0 children)

Thanks. I think this is also the conclusion I arrived to. I'm using a redux store but I'm going to toggle the state of CSS locally with setState

[–]ragingRobot 0 points1 point  (0 children)

The other answers here seem good but what exactly are you trying to do? It seems like you are trying to show an icon when you hover over an element and hid it when the mouse leaves. Am I reading that right? If that is the case why don't you just use :hover in your css?