Three.js in React.js

[react-three-renderer](https://github.com/toxicFork/react-three-renderer)を使うことで、Three.jsのオブジェクトをJSXの中でコンポーネントとして記述することができます。

## Example (w/redux)

`scene`, `camera`, `mesh`などThree.jsのオブジェクトがcomponentとして提供されていて、通常のReactComponent同様にsetStateで描画が更新されます。アニメーション処理は`onAnimate`内に記述します。

```js:example.jsx
import React from 'react';
import React3 from 'react-three-renderer';
import { connect } from 'react-redux'
import * as THREE from 'three';
import { fetchTexture } from '../actions/texture';

const pi = Math.PI;
const rad = pi / 180;
const width = window.innerWidth;
const height = window.innerHeight;

class Example extends React.Component {
  state = {
    dirZ: -1,
    dirRad: rad,
    planePosition: new THREE.Vector3(0, 0, 500),
    planeRotation: new THREE.Euler(0, 0, 0)
  };

  cameraPosition = new THREE.Vector3(0, 100, 500);
  lightPosition = new THREE.Vector3(0, 100, 30);

  componentDidMount() {
    this.props.fetchPhotosWithTexture();
  }

  onAnimate() {
    this.setState({
      planePosition: new THREE.Vector3(
        this.state.planePosition.x,
        this.state.planePosition.y,
        this.state.planePosition.z + this.state.dirZ
      ),
      planeRotation: new THREE.Euler(
        this.state.planeRotation.x + this.state.dirRad,
        this.state.planeRotation.y,
        this.state.planeRotation.z + this.state.dirRad
      )
    });
  }

  render() {
    return (
      <React3
        mainCamera="camera"
        width={width}
        height={height}
        clearColor={0x000000}
        pixelRatio={window.devicePixelRatio}
        onAnimate={this.onAnimate.bind(this)}
      >
        <scene>
          <directionalLight position={this.lightPosition} />
          <ambientLight color={0xaaaaaa} />
          <perspectiveCamera
            name="camera"
            fov={45}
            aspect={width / height}
            near={1}
            far={2000}
            position={this.cameraPosition}
          />
          <gridHelper size={200} step={50} />
          <axisHelper size={1000} />

          {this.props.texture ?
            <mesh
              position={this.state.planePosition}
              rotation={this.state.planeRotation}
            >
              <planeGeometry
                width={this.props.texture.image.width / 2}
                height={this.props.texture.image.height / 2}
              />
              <meshLambertMaterial
                map={this.props.texture}
                side={THREE.DoubleSide}
              />
            </mesh>
          : null}
        </scene>
      </React3>
    );
  }
}

export default connect(
  state => ({ texture: state.texture }),
  { fetchTexture }
)(Example)
```

![雑なsample](https://qiita-image-store.s3.amazonaws.com/0/3939/33b7e73b-8f44-f0a7-d513-33c904d7f1fe.gif)


## Debug

便利なことにReact Developer Toolsも通常のReact.jsと同じように使うことができます。
（さすがにprops, stateはReadOnlyになっていてこちらから動的に変えることはできないようですが）

<img width="1370" alt="スクリーンショット 2016-12-25 22.48.43.png" src="https://qiita-image-store.s3.amazonaws.com/0/3939/eebac807-04fb-17d7-3e82-dcbe58abe628.png">


## 所感

私はReact.js製のアプリケーション内にThree.jsのコンテンツを表示するために使いましたが、Three.jsのオブジェクトの構造をより明示的に記述できるのは良いですね。React.js, Three.jsどちらも触ったことがあれば[API Documentation](https://github.com/toxicFork/react-three-renderer/wiki/API-Reference)を見ればすぐに書けるかと思います。