2017-06-06 63 views
1

我想讓我的瀏覽器將一些DOM事件發送到React VR組件中。React VR組件和本地模塊代碼之間的持久橋樑

我得到的最接近的是使用「native模塊」的代碼。

(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後臺工作者的模式是什麼?

回答

1

我想通了......有點。

訣竅是創建我自己的「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是有史以來意味着被曝光給消費者。

但是,除非有更好的選擇,否則我認爲我會繼續這樣做。