Dileet
Dileet

Reputation: 2064

React hover to show image. Hover isn't working

Still trying to learn React. I'm trying to show an image when you hover. This is my Item component.

import React from 'react';


import Eyecon from '../../static/eye.svg';


class Item extends React.Component {
    constructor(props) {
        super(props);
        this.displayName = 'Item';
        this.state = {
            hover: false
        };
    }
    mouseOver() {
        this.setState({hover: true});
    }
    mouseOut() {
        this.setState({hover: false});
    }
    render() {
      const { item, i } = this.props;
        return (
            <div className="grid-box" onMouseOver={this.mouseOver} onMouseOut={this.mouseOut}>
            {this.state.hover ? (<img src={Eyecon}/>) : null}       
            </div>
        )
    }
}


export default Item;

How would I make it so only the item I hover over shows the image?

Upvotes: 1

Views: 8868

Answers (3)

jmancherje
jmancherje

Reputation: 6633

This is just a 'this' binding issue. Put a console.log inside of your mouseOver and mouseOut methods and you'll notice that your state isn't changing.

There are many ways to bind the 'this' context in your class methods. I'll show you three ways to do it in this example (DO NOT do all three methods, just choose one).

import React from 'react';
import Eyecon from '../../static/eye.svg';

class Item extends React.Component {
    constructor(props) {
        super(props);
        this.displayName = 'Item';
        // 1. bind your functions in the constructor.
        this.mouseOver = this.mouseOver.bind(this);
        this.mouseOut = this.mouseOut.bind(this);
        this.state = {
            hover: false
        };
    }

    // 2. bind it with fat arrows.
    mouseOver = () => {
        this.setState({hover: true});
    }
    mouseOut() {
        this.setState({hover: false});
    }
    render() {
      const { item, i } = this.props;
        // 3. bind them in the render method (not recommended for performance reasons)
        return (
            <div className="grid-box" onMouseOver={this.mouseOver.bind(this)} onMouseOut={this.mouseOut.bind(this)}>
            {this.state.hover ? (<img src={Eyecon}/>) : null}       
            </div>
        )
    }
}


export default Item;

Here's an explanation of different ways to bind your 'this' context in react using ES6 classes: http://egorsmirnov.me/2015/08/16/react-and-es6-part3.html

Upvotes: 2

Chris
Chris

Reputation: 59491

The other solutions suggested are perfectly valid, however you can solve this easily by just converting your functions to ES6 arrow functions.

An arrow function expression has a shorter syntax compared to function expressions and lexically binds the this value (does not bind its own this, arguments, super, or new.target). Arrow functions are always anonymous.

Like so:

mouseOver = () => {
  this.setState({hover: true});
}
mouseOut = () => {
  this.setState({hover: false});
}

Simple.

Upvotes: 0

luiscrjr
luiscrjr

Reputation: 7258

Maybe it's because you have to bind mouseOver and mouseOut calls in order to use this.setState inside them.

Replace:

<div className="grid-box" onMouseOver={this.mouseOver} onMouseOut={this.mouseOut}>

with:

<div className="grid-box" onMouseOver={this.mouseOver.bind(this)} onMouseOut={this.mouseOut.bind(this)}>

Upvotes: 0

Related Questions