I am working on a VR project which is has 2 user roles, a leader (who sets up and configures a VR session) and clients (who connect to this session). I am using a Native module to perform a DOM overlay in which several buttons related to session configuration are displayed for the leader. I was wondering if it is possible to call a function within the React360 code directly from a Native Module (i.e. not as a callback as the event would originate from the Native Module)? This could be a complete anti-pattern, I can't seem to see a way of doing it...
I actually got this working with the following:
In client.js I passed the context to the DOM overlay native module:
const r360 = new ReactInstance(bundle, parent, {
// Add custom options here
fullScreen: true,
cursorVisibility: "visible",
nativeModules: [
// Create an instance of the DOM overlay module and pass the context
ctx => new DashboardModule(ctx, domDashboardContainer)
],
...options,
});
In the dashboard native module :
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;
};
....
constructor(ctx, overlayContainer) {
super('DashboardModule');
...
this._rnctx = ctx;
this._bridgeName = 'BrowserBridge';
}
onButtonClick() {
....
this._emit('nativeButtonClicked', event);
}
_emit(name, event) {
if (!this._rnctx) {
return;
}
const eventOb = eventToOb(event);
this._rnctx.callFunction(this._bridgeName, 'notifyEvent', [name, eventOb]);
}
...
and in my index.js
...
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);
....
constructor(props) {
super(props);
this.onBrowserEvent = this.onBrowserEvent.bind(this);
...
}
componentWillMount() {
this.unsubscribe = browserBridge.subscribe(this.onBrowserEvent);
}
onBrowserEvent(name, event) {
// Do action on event here
}
componentWillUnmount() {
if (this.unsubscribe) {
this.unsubscribe();
delete this.unsubscribe;
}
}
If there is a better way of doing this please let me know.