简体   繁体   中英

react-input-range does not trigger events(onChange, onClick) inside react-leaflet Map

I have here some interesting case! I'm using a react-input-range inside a react-leaflet Marker Popup

Which is something like this:

import React from 'react';
import { Map as LeafletMap, Marker, Popup, TileLayer } from 'react-leaflet';
import InputRange from 'react-input-range';

export default class MapPage extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: { min: 2, max: 200 },
      name: 'sample name',
    };
  }
  render() {
    return (
      <div>
        {/*
          * This input range outside LeafletMap works
        */}
        <InputRange
          maxValue={300}
          minValue={0}
          value={this.state.value}
          onChange={value => this.setState({ value })}
        />
        <LeafletMap center={[0, 0]} zoom={16}>
          <TileLayer
            attribution="&copy; <a href=&quot;http://osm.org/copyright&quot;>OpenStreetMap</a> contributors"
            url="http://{s}.tile.osm.org/{z}/{x}/{y}.png"
          />
          <Marker position={[0, 0]}>
            <Popup>
              {/*
                * This input below works
              */}
              <input
                value={this.state.name}
                onChange={({ target }) => this.setState({ name: target.value })}
              />
              {/*
                * This input range INSIDE LeafletMap does not work
              */}
              <InputRange
                maxValue={300}
                minValue={0}
                value={this.state.value}
                onChange={value => this.setState({ value })}
              />
            </Popup>
          </Marker>
        </LeafletMap>
      </div>
    );
  }
}

What I know so far

  • The input range component works outside the LeafletMap component.
  • Native input works inside the LeafletMap component!
  • I've confirmed that a native input works inside the popup! The input range works on mobile(android chrome browser)! (swipe & click events)

Any ideas how to make input range work inside react-leaflet map ?

Here's a few more details that might help:

  • react-leaflet: ^2.0.0-rc.3
  • react: 16.4.2
  • react-input-range: ^1.3.0

Testing Env

Browsers: Chrome 64.0.32, Firefox 61 and Safari 11.1

OS: Mac OSX High Sierra 10.13.5

Codepen: https://codepen.io/codepen-theo/pen/OwdLXY?editors=0010

I have figured out what's happening. But I'm not sure there's a good way to get it to work as you want.

What happens is that leaflet.js will call event.stopPropagation() on the mousedown event when it bubbles to the popup element. This blocks reacts synthetic events from working as expected. React's event propagation is handled independently of the native bubbling / capturing.

https://github.com/Leaflet/Leaflet/blob/master/src/layer/Popup.js#L185

You can monkey patch the the event listener on the popup wrapper. See this example:

https://codepen.io/haakenlid/pen/ejxNKE

This works by simply removing one of the preventDefault event listener that leaflet.js has attached to the plugin wrapper node. (In a very hacky way)

class MyPopup extends React.Component {
  componentDidMount(){
    if (!this.popup) return
    const el = this.popup.leafletElement
    el._initLayout()
    const wrapper = el._wrapper
    wrapper.removeEventListener('mousedown', wrapper._leaflet_events['mousedown6'])
    console.log('mount')
  }
  render(){
    return <Popup ref={ el=>this.popup = el } {...this.props} />
  }
}

This is just a proof of concept. There's a high likelihood that it will break again with future versions of leaflet.js (or in some other way).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM