Persistent bridge between a React VR component and native module code

三世轮回 提交于 2019-12-01 12:02:56

I figured it out... sort of.

The trick was to create my own "BatchedBridge", which I can then reach using the callFunction() from the context.

(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]);
    }
}

This feels very hacky, as it doesn't seem BatchedBridge was ever meant to be exposed to consumers.

But until there is a better option, I think I'll go with this.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!