React-native-web: what's the idiomatic way to apply an onHover handler?

Created on 16 Sep 2016  路  6Comments  路  Source: necolas/react-native-web

It seems to me that _React Native Web_ should have an onHover prop just as <View> and <Text> support onPress. Perhaps I'm missing something.

Most helpful comment

I wrote a component that uses setNativeProps to set styles on hover in case anyone wants to see what that looks like:

import React from 'react'
import { View } from 'react-native'

class HoverableView extends React.Component {
  setStyles = (styles) => {
    this.root.setNativeProps({
      style: styles,
    })
  }

  render() {
    const { onHover, style, ...passThrough } = this.props
    return (
      <View
        ref={(component) => { this.root = component }}
        onMouseEnter={() => this.setStyles(onHover)}
        onMouseLeave={() => this.setStyles(style)}
        style={style}
        {...passThrough}
      />
    )
  }
}

export default HoverableView

Called like this:

<HoverableView
  style={{ backgroundColor: 'transparent', flex: 1 }}
  onHover={{ backgroundColor: '#ff0000' }}
>
  <Text>Foo</Text>
</HoverableView>

One thing to be aware of is that if a style attribute is passed through onHover but is not in the style prop, it will not be overwritten onMouseLeave. (That's why backgroundColor: 'transparent' is set in the style prop of the example)

All 6 comments

The thing is you need 2 callbacks to know on and off. But yeah, onMouseEnter & onMouseLeave are related to mouse...

excellent thanks @MoOx that solves my problem--didn't know those callbacks were available. it's not available on Touchable components if anyone's wondering, but on <Text> and probably I assume <View as well.

It's starting to seem like a library of web-specific react components should emerge, similar to how the tvOS efforts require components for their unique way of "focusing" elements. For example, <TouchableOpacityHover> would have 2 different opacity based on if it's pressed or simply hovered.

I created a utility component to make it easy to add a hover style:

HoverableOpacity.js

import React, { Component } from 'react'
import { TouchableOpacity } from 'react-native'

export default class HoverableOpacity extends Component {
  constructor(props) {
    super(props)
    this.state = {}
  }

  render() {
    const { outerStyle, hoverStyle } = this.props

    return (
      <TouchableOpacity
        activeOpacity={1}
        style={[{ cursor: 'inherit' }, outerStyle, this.state.hover ? hoverStyle : {}]}
        onMouseEnter={() => this.setState({ hover: true })}
        onMouseLeave={() => this.setState({ hover: false })}
      >
        <TouchableOpacity {...this.props} />
      </TouchableOpacity>
    )
  }
}

HoverableOpacity.propTypes = {
  hoverStyle: React.PropTypes.shape({}),
  outerStyle: React.PropTypes.shape({}),
}

Usage

Use HoverableOpacity in place of TouchableOpacity.

It can take two new props:

hoverStyle

Style to apply while component is hovered.

E.g.:
hoverStyle={{ backgroundColor: 'hsla(0,0%,100%,0.1)' }}

outerStyle

Style applied to the Hoverable container.

Useful for adding margins outside the hover.

E.g.:
outerStyle={{ margin: 30 }}

You should use setNativeProps (like the touchables do) to update the style without triggering a render of the sub tree.

I wrote a component that uses setNativeProps to set styles on hover in case anyone wants to see what that looks like:

import React from 'react'
import { View } from 'react-native'

class HoverableView extends React.Component {
  setStyles = (styles) => {
    this.root.setNativeProps({
      style: styles,
    })
  }

  render() {
    const { onHover, style, ...passThrough } = this.props
    return (
      <View
        ref={(component) => { this.root = component }}
        onMouseEnter={() => this.setStyles(onHover)}
        onMouseLeave={() => this.setStyles(style)}
        style={style}
        {...passThrough}
      />
    )
  }
}

export default HoverableView

Called like this:

<HoverableView
  style={{ backgroundColor: 'transparent', flex: 1 }}
  onHover={{ backgroundColor: '#ff0000' }}
>
  <Text>Foo</Text>
</HoverableView>

One thing to be aware of is that if a style attribute is passed through onHover but is not in the style prop, it will not be overwritten onMouseLeave. (That's why backgroundColor: 'transparent' is set in the style prop of the example)

I created an example that also implements pseudo classes other than hover.
As an example, please try it.
https://github.com/Shagamii/pseudo-class-example/blob/master/src/AccessibleComponent.js

Was this page helpful?
0 / 5 - 0 ratings

Related issues

blairio picture blairio  路  3Comments

buffaloDeveloper picture buffaloDeveloper  路  3Comments

iksent picture iksent  路  3Comments

necolas picture necolas  路  3Comments

tgh picture tgh  路  3Comments