How do you Hover in ReactJS? - onMouseLeave not re

2020-01-27 15:15发布

How can you achieve either a hover event or active event in ReactJS when you do inline styling?

I've found that the onMouseEnter, onMouseLeave approach is buggy, so hoping there is another way to do it.

Specifically, if you mouse over a component very quickly, only the onMouseEnter event is registered. The onMouseLeave never fires, and thus can't update state... leaving the component to appear as if it still is being hovered over. I've noticed the same thing if you try and mimic the ":active" css pseudo-class. If you click really fast, only the onMouseDown event will register. The onMouseUp event will be ignored... leaving the component appearing active.

Here is a JSFiddle showing the problem: https://jsfiddle.net/y9swecyu/5/

Video of JSFiddle with problem: https://vid.me/ZJEO

The code:

var Hover = React.createClass({
    getInitialState: function() {
        return {
            hover: false
        };
    },
    onMouseEnterHandler: function() {
        this.setState({
            hover: true
        });
        console.log('enter');
    },
    onMouseLeaveHandler: function() {
        this.setState({
            hover: false
        });
        console.log('leave');
    },
    render: function() {
        var inner = normal;
        if(this.state.hover) {
            inner = hover;
        }

        return (
            <div style={outer}>
                <div style={inner}
                    onMouseEnter={this.onMouseEnterHandler}
                    onMouseLeave={this.onMouseLeaveHandler} >
                    {this.props.children}
                </div>
            </div>
        );
    }
});

var outer = {
    height: '120px',
    width: '200px',
    margin: '100px',
    backgroundColor: 'green',
    cursor: 'pointer',
    position: 'relative'
}

var normal = {
    position: 'absolute',
    top: 0,
    bottom: 0,
    left: 0,
    right: 0,
    backgroundColor: 'red',
    opacity: 0
}

var hover = {
    position: 'absolute',
    top: 0,
    bottom: 0,
    left: 0,
    right: 0,
    backgroundColor: 'red',
    opacity: 1
}

React.render(
    <Hover></Hover>,         
    document.getElementById('container')
)

13条回答
▲ chillily
2楼-- · 2020-01-27 15:53

you can use onMouseOver={this.onToggleOpen} and onMouseOut={this.onToggleOpen} to muse over and out on component

查看更多
Rolldiameter
3楼-- · 2020-01-27 15:54

A package called styled-components can solve this problem in an ELEGANT way.

Reference

  1. Glen Maddern - Styling React Apps with Styled Components

Example

const styled = styled.default
const Square = styled.div`
  height: 120px;
  width: 200px;
  margin: 100px;
  background-color: green;
  cursor: pointer;
  position: relative;
  &:hover {
    background-color: red;
  };
`
class Application extends React.Component {
  render() {
    return (
      <Square>
      </Square>
    )
  }
}

/*
 * Render the above component into the div#app
 */
ReactDOM.render(<Application />, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.6.1/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.6.1/react-dom.min.js"></script>
<script src="https://unpkg.com/styled-components/dist/styled-components.min.js"></script>
<div id='app'></div>

查看更多
Rolldiameter
4楼-- · 2020-01-27 16:00

I know It's been a while since this question was asked but I just run into the same issue of inconsistency with onMouseLeave() What I did is to use onMouseOut() for the drop-list and on mouse leave for the whole menu, it is reliable and works every time I've tested it. I saw the events here in the docs: https://facebook.github.io/react/docs/events.html#mouse-events here is an example using https://www.w3schools.com/bootstrap/bootstrap_dropdowns.asp:

handleHoverOff(event){
  //do what ever, for example I use it to collapse the dropdown
  let collapsing = true;
  this.setState({dropDownCollapsed : collapsing });
}

render{
  return(
    <div class="dropdown" onMouseLeave={this.handleHoverOff.bind(this)}>
      <button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">Dropdown Example
      <span class="caret"></span></button>
      <ul class="dropdown-menu" onMouseOut={this.handleHoverOff.bind(this)}>
        <li><a href="#">bla bla 1</a></li>
        <li><a href="#">bla bla 2</a></li>
        <li><a href="#">bla bla 3</a></li>
      </ul>
    </div>
  )
}
查看更多
乱世女痞
5楼-- · 2020-01-27 16:01

Use Radium!

The following is an example from their website:

var Radium = require('radium');
var React = require('react');
var color = require('color');

@Radium
class Button extends React.Component {
  static propTypes = {
    kind: React.PropTypes.oneOf(['primary', 'warning']).isRequired
  };

  render() {
    // Radium extends the style attribute to accept an array. It will merge
    // the styles in order. We use this feature here to apply the primary
    // or warning styles depending on the value of the `kind` prop. Since its
    // all just JavaScript, you can use whatever logic you want to decide which
    // styles are applied (props, state, context, etc).
    return (
      <button
        style={[
          styles.base,
          styles[this.props.kind]
        ]}>
        {this.props.children}
      </button>
    );
  }
}

// You can create your style objects dynamically or share them for
// every instance of the component.
var styles = {
  base: {
    color: '#fff',

    // Adding interactive state couldn't be easier! Add a special key to your
    // style object (:hover, :focus, :active, or @media) with the additional rules.
    ':hover': {
      background: color('#0074d9').lighten(0.2).hexString()
    }
  },

  primary: {
    background: '#0074D9'
  },

  warning: {
    background: '#FF4136'
  }
};

查看更多
贼婆χ
6楼-- · 2020-01-27 16:02

Note: This answer was for a previous version of this question where the question asker was trying to use JavaScript to apply css styles… which can simply be done with CSS.

A simple css-only solution.

For applying basic styles, CSS is simpler and more performant that JS solutions 99% of the time. (Though more modern CSS-in-JS solutions — eg. React Components, etc — are arguably more maintainable.)

Run this code snippet to see it in action…

.hover-button .hover-button--on,
.hover-button:hover .hover-button--off {
  display: none;
}

.hover-button:hover .hover-button--on {
  display: inline;
}
<button class='hover-button'>
  <span class='hover-button--off'>Default</span>
  <span class='hover-button--on'>Hover!</span>
</button>

查看更多
Summer. ? 凉城
7楼-- · 2020-01-27 16:04

If you can produce a small demo showing the onMouseEnter / onMouseLeave or onMouseDown / onMouseUp bug, it would be worthwhile to post it to ReactJS's issues page or mailing list, just to raise the question and hear what the developers have to say about it.

In your use case, you seem to imply that CSS :hover and :active states would be enough for your purposes, so I suggest you use them. CSS is orders of magnitude faster and more reliable than Javascript, because it's directly implemented in the browser.

However, :hover and :active states cannot be specified in inline styles. What you can do is assign an ID or a class name to your elements and write your styles either in a stylesheet, if they are somewhat constant in your application, or in a dynamically generated <style> tag.

Here's an example of the latter technique: https://jsfiddle.net/ors1vos9/

查看更多
登录 后发表回答