Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom events in React Native Android native UI component

I'd like to use OpenStreetMap tiles in my React Native app on Android, so I'm trying to wrap the OSMDroid native UI component as described here. For the most part it's working fine, but I'm having trouble figuring out how to correctly handle events, specifically onScroll and onZoom.

With OSMDroid, you set a DelayedMapListener to handle the events, which is pretty straightforward. I've confirmed that events are being handle correctly Java-side up until the point where the JS code should be triggered. However, they're not triggering my JavaScript code.

Based on the documentation, I've implemented the event handlers in Java in the createViewInstance method of my view manager:

map.setMapListener(new DelayedMapListener(new MapListener() {
    public boolean onScroll(ScrollEvent event) {
        WritableMap eventData = Arguments.createMap();

        // Fill in eventData; details not important

        ReactContext reactContext = (ReactContext)map.getContext();
        reactContext.getJSModule(RCTEventEmitter.class).receiveEvent(
            map.getId(),
            "topChange",
             eventData);

        return true;
    }

    public boolean onZoom(ZoomEvent event) {
        // Basically the same as above
    }
}, 100));

The relevant part of my JS code is basically identical to the code in the documentation linked above:

class OSMDroidMapView extends Component {
    constructor(props) {
        super(props);
        this._onChange = this._onChange.bind(this);
    }

    _onChange(event: Event) {
        console.log(event);
        // Handle event data
    }

    render() {
        return <OSMDroidMapView {...this.props} onChange={this._onChange}/>
    }
}

There are no errors or any signs that anything is wrong. The Java event handler code is called correctly. There's just no sign of anything happening in the JS code when an event occurs. Does anyone know how to do this correctly? I feel like I must be missing some basic concept here.

like image 548
btmcnellis Avatar asked Feb 22 '16 03:02

btmcnellis


1 Answers

To send custom events to Javascript you can use RCTDeviceEventEmitter:

In the Native side:

import com.facebook.react.modules.core.DeviceEventManagerModule;

...

public boolean onScroll(ScrollEvent event) {
    WritableMap eventData = Arguments.createMap();

    // Fill in eventData; details not important

    ReactContext reactContext = (ReactContext)map.getContext();
    reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
                .emit("YouCustomEventName", eventData);

    return true;
}

Inside your JS module you just have to register a listener using DeviceEventEmitter:

class OSMDroidMapView extends Component {
    constructor(props) {
        super(props);
        this._onChange = this._onChange.bind(this);
    }

    componentWillMount() {
        DeviceEventEmitter.addListener('YouCustomEventName', this._onChange);
    }

    componentWillUnmount() {
        DeviceEventEmitter.removeListener('YouCustomEventName', this._onChange);
    }

    _onChange(event: Event) {
        console.log(event);
        // Handle event data
    }

    render() {
        return <OSMDroidMapView {...this.props} onChange={this._onChange}/>
    }
}

Hope it helps.

like image 183
Bertrand Avatar answered Sep 25 '22 00:09

Bertrand