Пользовательские события в React Собственный компонент пользовательского интерфейса Android

Я хотел бы использовать плитки OpenStreetMap в своем приложении React Native на Android, поэтому я пытаюсь обернуть собственный компонент пользовательского интерфейса OSMDroid, как описано здесь. По большей части он работает нормально, но мне трудно понять, как правильно обрабатывать события, в частности onScroll и onZoom.

В OSMDroid вы устанавливаете DelayedMapListener для обработки событий, что довольно просто. Я подтвердил, что события обрабатываются правильно со стороны Java вплоть до момента, когда должен запускаться JS-код. Однако они не запускают мой код JavaScript.

Основываясь на документации, я реализовал обработчики событий в Java в методе createViewInstance моего диспетчера просмотров:

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));

Соответствующая часть моего JS-кода в основном идентична коду в приведенной выше документации:

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}/>
    }
}

Нет никаких ошибок или признаков того, что что-то не так. Код обработчика событий Java вызывается правильно. В случае возникновения события в коде JS ничего не происходит. Кто-нибудь знает, как это сделать правильно? Я чувствую, что мне, должно быть, недостает базовой концепции.

Ответы

Ответ 1

Чтобы отправить пользовательские события в Javascript, вы можете использовать RCTDeviceEventEmitter:

В родной части:

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;
}

Внутри вашего JS-модуля вам просто нужно зарегистрировать прослушиватель, используя 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}/>
    }
}

Надеюсь, это поможет.