Постоянный мост между компонентом React VR и собственным кодом модуля

1

Я пытаюсь, чтобы мой браузер отправил некоторые события DOM в компоненты React VR.

Самое близкое, что я получил, это этот код с использованием "родных модулей".

(client.js)

const windowEventsModule = new WindowEventsModule();

function init(bundle, parent, options) {
  const vr = new VRInstance(bundle, 'WelcomeToVR', parent, {
    ...options,
    nativeModules: [windowEventsModule]
  });

  windowEventsModule.init(vr.rootView.context);

  vr.start();

  return vr;
}

window.ReactVR = {init};

(WindowEventsModule.js)

export default class WindowEventsModule extends Module {
  constructor() {
    super('WindowEventsModule');

    this.listeners = {};

    window.onmousewheel = event => {
      this._emit('onmousewheel', event);
    };
  }

  init(rnctx) {
    this._rnctx = rnctx;
  }

  _emit(name, ob) {
    if (!this._rnctx) {
      return;
    }

    Object.keys(this.listeners).forEach(key => {
      this._rnctx.invokeCallback(this.listeners[key], [ob]);
    });
  }

  onMouseWheel(listener) {
    const key = String(Math.random());
    this.listeners[key] = listener;
    return () => {
      delete this.listeners[key];
    };
  }
}

Поэтому мои компоненты теперь могут вызывать WindowEvents.onMouseWheel(function() {}) и получать обратный вызов из мира DOM.

К сожалению, это работает только один раз. RN, по-видимому, аннулирует мой обратный вызов после его вызова.

Я также исследовал this._rnctx.callFunction(), который может вызывать произвольную функцию на том, что называется "вызываемым модулем". Я не вижу, как я могу добраться оттуда до моих компонентов.

Есть что-то, чего я не хватает? Каков шаблон для подачи произвольных сообщений из родного мира в рабочий стол ReactVR?

Теги:
react-native
react-vr

1 ответ

2

Я понял это... вроде как.

Хитрость заключалась в том, чтобы создать свой собственный "BatchedBridge", который я могу затем использовать с помощью функции callFunction() из контекста.

(index.vr.js)

import React from 'react';
import {AppRegistry, asset, Pano, View} from 'react-vr';
import BatchedBridge from 'react-native/Libraries/BatchedBridge/BatchedBridge';
import lodash from 'lodash';

class BrowserBridge {
    constructor() {
        this._subscribers = {};
    }

    subscribe(handler) {
        const key = String(Math.random());
        this._subscribers[key] = handler;
        return () => {
            delete this._subscribers[key];
        };
    }

    notifyEvent(name, event) {
        lodash.forEach(this._subscribers, handler => {
            handler(name, event);
        });
    }
}

const browserBridge = new BrowserBridge();
BatchedBridge.registerCallableModule(BrowserBridge.name, browserBridge);

export default class WelcomeToVR extends React.Component {
    constructor(props) {
        super(props);

        this.onBrowserEvent = this.onBrowserEvent.bind(this);
    }

    componentWillMount() {
        this.unsubscribe = browserBridge.subscribe(this.onBrowserEvent);
    }

    onBrowserEvent(name, event) {
        // Do the thing here
    }

    componentWillUnmount() {
        if (this.unsubscribe) {
            this.unsubscribe();
            delete this.unsubscribe;
        }
    }

    render() {
        //...
    }
};

AppRegistry.registerComponent('WelcomeToVR', () => WelcomeToVR);

(WindowEventsModule.js)

import {Module} from 'react-vr-web';
import lodash from 'lodash';

const eventToOb = (event) => {
    const eventOb = {};
    for (let key in event) {
        const val = event[key];
        if (!(lodash.isFunction(val) || lodash.isObject(val))) {
            eventOb[key] = val;
        }
    }
    return eventOb;
};

export default class WindowEventsModule extends Module {
    constructor() {
        super('WindowEventsModule');

        this._bridgeName = 'BrowserBridge';

        window.onmousewheel = event => {
            this._emit('onmousewheel', event);
        };
    }

    init(rnctx) {
        this._rnctx = rnctx;
    }

    _emit(name, event) {
        if (!this._rnctx) {
            return;
        }

        const eventOb = eventToOb(event);

        this._rnctx.callFunction(this._bridgeName, 'notifyEvent', [name, eventOb]);
    }
}

Это чувствует себя очень взломанным, поскольку, похоже, BatchedBridge никогда не подвергался воздействию потребителей.

Но пока есть лучший вариант, я думаю, что я пойду с этим.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню