facebookarchive / react-360

Create amazing 360 and VR content using React
https://facebook.github.io/react-360
Other
8.73k stars 1.23k forks source link

React component rendered within ReactVR component #242

Closed hjnieuwenhuizen closed 7 years ago

hjnieuwenhuizen commented 7 years ago

Hi, this may be a silly question and I apologize in advance if that is the case, but I am struggling to get a React component to render within one of my ReactVR components. Do you have a basic example of how i can do this?

React Component:

import React from 'react'

export default class Billboard extends React.Component {
  constructor() {
    super()
    this.state = {
    }
  }
  render() {
    return (
      <h1>HELLO</h1>
    )
  }
}

ReactVR Component

import React from 'react'
import {AppRegistry, asset, Pano, Text, View, Model, Box} from 'react-vr'
import Styles from './styles/styles'
import Billboard from './components/billboard'

export default class View extends React.Component {
  constructor() {
    super()
    this.state = {

    }
  }
  render() {
    return (
      <View>
        <Billboard/>
        <Pano source={asset(this.state.view)}/>
      </View>
    )
  }
}

AppRegistry.registerComponent('View', () => View)
mikearmstrong001 commented 7 years ago

1) React VR is based on React Native which doesn't work with DOM elements 2) As the React code is running in a webworker there is no ability to create/destroy dom elements

You would need create

native view information can be found at https://github.com/facebook/react-vr/blob/master/docs/NativeModules.md

hjnieuwenhuizen commented 7 years ago

Sorry Mike I am really struggling with this. Are you able to give me a small code snippet on my example above. Pretty please. Also not 100% what modules i need to import etc.

mikearmstrong001 commented 7 years ago

I'll try and put something together over the weekend

hjnieuwenhuizen commented 7 years ago

Shot dude. I will buy you a beer one day :-)

hjnieuwenhuizen commented 7 years ago

I think my best bet is to iFrame my ReactVR app into my current App. Are you able to make the code snippet reflect how you would post messages between these two.

hjnieuwenhuizen commented 7 years ago

Hi Mike, did you find a chance to put together a simple code snippet? Or could you guide me to an example. Struggling to find much content out there on this matter.

mikearmstrong001 commented 7 years ago

You'll have to work out the specifics for your requirements but attached should help give you a starter. With this you should have a means to create and drive with a dom element

client.js

/**
 * The examples provided by Oculus are for non-commercial testing and
 * evaluation purposes only.
 *
 * Oculus reserves all rights not expressly granted.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL
 * OCULUS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

import {VRInstance} from 'react-vr-web';
import {Module} from 'react-vr-web';
import * as THREE from 'three';
import * as ReactVR from 'react-vr-web';
import * as OVRUI from 'ovrui';
import merge from '../../../ReactVR/ReactVR/js/Utils/merge';

class RCTTestDom extends ReactVR.RCTBaseView {
  constructor(guiSys: GuiSys) {
    super();
    this.view = new OVRUI.UIView(guiSys);
    this.newContent = document.createTextNode("Hi there and greetings!");
    document.body.appendChild(this.newContent)
  }

  discard() {
    super.discard();
    document.body.removeChild(this.newContent);
    this.newContent = null;
  }

  static describe() {
    return merge(super.describe(), {
      // declare the native props sent from react to runtime
      NativeProps: {
      },
    });
  }
}

function init(bundle, parent, options) {
  // Create a scene so we can add to it; otherwise the VRInstance creates one.
  const scene = new THREE.Scene();
  // Create Native Module so React context can modify native (Three.js) cube.
  const cubeModule = new CubeModule();

  const vr = new VRInstance(bundle, 'CubeSample', parent, {
    cursorVisibility: 'visible',
    nativeModules: [cubeModule],
    customViews: [{name: 'TestDom', view: RCTTestDom}],
    scene: scene,
  });

  // Custom scene setup goes here. Add a cube to the scene.
  // Must be done after providing the scene to VRInstance above.
  const cube = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), new THREE.MeshBasicMaterial());
  cube.position.z = -4;
  scene.add(cube);

  // Give cubeModule a handle to our cube.
  cubeModule.init(cube);

  vr.render = function(timestamp) {
    // Custom per-frame updates go here. Bounce the cube up and down.
    const seconds = timestamp / 1000;
    cube.position.x = 0 + 1 * Math.cos(seconds);
    cube.position.y = 0.2 + 1 * Math.abs(Math.sin(seconds));
  };

  // Begin the animation loop
  vr.start();
  return vr;
}

export default class CubeModule extends Module {
  // CubeModule is a React Native Module, which implements functionality
  // that can be called asynchronously across the React Native brige.

  // Constructor calls super() with one argument: module name.
  constructor() {
    super('CubeModule');
  }

  // Called directly after the module is created.
  init(cube) {
    this.cube = cube;
  }

  // Change the cube material color to the given value.
  // Called remotely by the CubeModule on the React side.
  changeCubeColor(color) {
    // THREE.Color() accepts either a six-digit hex color or a CSS style.
    // e.g. 0xff0000, 'rgb(255,0,0)', 'red'
    this.cube.material.color = new THREE.Color(color);
  }
}

window.ReactVR = {init};

index.vr.js

/**
 * The examples provided by Oculus are for non-commercial testing and
 * evaluation purposes only.
 *
 * Oculus reserves all rights not expressly granted.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL
 * OCULUS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

'use strict';
/**
 *
 * CubeSample displays a ReactVR button and text, along with a Three.js cube.
 * The cube will change color when the button is selected. The React context
 * and Three.js scene are in separate threads, so they communicate over the
 * React Native bridge via the CubeModule, a custom Native Module. This
 * shows how ReactVR UI elements can be added to an existing Three.js scene.
 */

import React from 'react';
import {AppRegistry, asset, Pano, Text, View, VrButton, NativeModules} from 'react-vr';

const NativeMethodsMixin = require('NativeMethodsMixin');
const StyleSheetPropType = require('StyleSheetPropType');
const LayoutAndTransformPropTypes = require('LayoutAndTransformPropTypes');
const ReactNativeViewAttributes = require('ReactNativeViewAttributes');
const requireNativeComponent = require('requireNativeComponent');
// Native Module defined in vr/client.js
const CubeModule = NativeModules.CubeModule;

const TestDom = React.createClass({
  mixins: [NativeMethodsMixin],

  propTypes: {
    ...View.propTypes,
    style: StyleSheetPropType(LayoutAndTransformPropTypes),
  },

  viewConfig: {
    uiViewClassName: 'TestDom',
    validAttributes: {
      ...ReactNativeViewAttributes.RCTView,
    },
  },

  getDefaultProps: function() {
    return {};
  },

  render: function() {
    return (
      <RKTestDom/>
    );
  },
});

const RKTestDom = requireNativeComponent('TestDom', TestDom, {
  nativeOnly: {},
});

/**
 * CubeSample implements a custom button that calls a native module method,
 * changing the color of a cube that is managed on the native (Three.js) side.
 */
class CubeSample extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      borderColor: 'rgba(0, 0, 0, 0)', // transparent
      btnColor: 'grey',
      cubeColor: 'yellow',
    };
    CubeModule.changeCubeColor(this.state.cubeColor);
  }

  render() {
    return (
      <View
        style={{
          transform: [{translate: [0, 0, -3]}],
          layoutOrigin: [0.5, 0, 0],
          alignItems: 'center',
        }}
      >
        <Pano source={asset('chess-world.jpg')} />
        <TestDom />
      </View>
    );
  }
}

AppRegistry.registerComponent('CubeSample', () => CubeSample);
upressplay commented 7 years ago

So, I was trying to get the CubeModule example working and I keep getting the following error. What am I doing wrong?

Uncaught TypeError: a.onBeforeRender is not a function

screen shot 2017-08-04 at 12 19 53 pm

import {VRInstance} from 'react-vr-web'; import {Module} from 'react-vr-web'; import as THREE from 'three'; import as ReactVR from 'react-vr-web'; import * as OVRUI from 'ovrui';

function init(bundle, parent, options) {

const scene = new THREE.Scene(); const cubeModule = new CubeModule();

const vr = new VRInstance(bundle, 'RaignVR', parent, { cursorVisibility: 'visible', nativeModules: [ cubeModule ], scene: scene, });

const cube = new THREE.Mesh( new THREE.BoxGeometry(1, 1, 1), new THREE.MeshBasicMaterial() );

cube.position.z = -4; scene.add(cube); cubeModule.init(cube);

vr.render = function(timestamp) { const seconds = timestamp / 1000; cube.position.x = 0 + (1 (Math.cos(seconds))); cube.position.y = 0.2 + (1 Math.abs(Math.sin(seconds))); };

// Begin the animation loop vr.start(); return vr; }

export default class CubeModule extends Module { // CubeModule is a React Native Module, which implements functionality // that can be called asynchronously across the React Native brige.

// Constructor calls super() with one argument: module name. constructor() { super('CubeModule'); }

// Called directly after the module is created. init(cube) { this.cube = cube; }

// Change the cube material color to the given value. // Called remotely by the CubeModule on the React side. changeCubeColor(color) { // THREE.Color() accepts either a six-digit hex color or a CSS style. // e.g. 0xff0000, 'rgb(255,0,0)', 'red' this.cube.material.color = new THREE.Color(color); } }

window.ReactVR = {init}; `