React VR组件与本机模块代码之间的持久桥接 [英] Persistent bridge between a React VR component and native module code

查看:100
本文介绍了React VR组件与本机模块代码之间的持久桥接的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图让我的浏览器将一些DOM事件发送到React VR组件中。

I am trying to have my browser send in some DOM events into the React VR components.

我得到的最接近的是使用本机模块的代码。

The closest I got is this code using "native modules."

(client.js)

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

(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世界获得回调。

So my components can now call WindowEvents.onMouseWheel(function() {}), and get a callback from the DOM world.

不幸的是,这仅适用一次。在调用后,RN显然会使我的回调无效。

Unfortunately, this only works once. RN will apparently invalidate my callback after it is called.

我还调查了 this._rnctx.callFunction(),它可以在称为可调用模块的东西上调用任意函数。我不知道如何从那里到我的组件。

I also investigated this._rnctx.callFunction(), which can call an arbitrary function on something called "callable module". I don't see how I can get from there to my components.

我缺少什么?从本地世界向ReactVR后台工作者提供任意消息的模式是什么?

Is there something I am missing? What's the pattern to feed arbitrary messages from the native world into the ReactVR background worker?

推荐答案

我想出来......排序。

I figured it out... sort of.

诀窍是创建我自己的BatchedBridge,然后我可以使用 callFunction()来自上下文。

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)

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

这感觉非常hacky,因为它似乎不太 BatchedBridge 曾经打算向消费者展示。

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.

这篇关于React VR组件与本机模块代码之间的持久桥接的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆