# orbitControls in React kills render

**URL:** <https://discourse.threejs.org/t/orbitcontrols-in-react-kills-render/24034>\
**Category:** Questions\
**Tags:** orbit-controls\
**Created:** [March 4, 2021, 12:08am UTC](https://discourse.threejs.org/t/orbitcontrols-in-react-kills-render/24034 "2021-03-04T00:08:04Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![NoahK](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/noahk/32/16776_2.png) [@NoahK](https://discourse.threejs.org/u/NoahK)\
**Post date:** [March 4, 2021, 12:08am UTC](https://discourse.threejs.org/t/orbitcontrols-in-react-kills-render/24034/1 "2021-03-04T00:08:04Z")

</div>

HI- I’m having a hard time adding orbitControls to a React component that uses THREEjs and was previously rendering correctly.

In my Viewport React component, I import orbitControls like this:

`import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";`

and looking at IntelliSense, it seems to be imported OK.

I have two rendering methods: **renderCanvas** and a new **renderAnimatedCanvas** like this:

```
renderCanvas() {

    this.state.renderer.render(this.state.scene, this.state.camera);

  }

  renderAnimatedCanvas() {

    // "top" rendering call
    this.state.renderer.render(this.state.scene, this.state.camera);

    let renderer = this.state.renderer;
    let camera = this.state.camera;
    let scene = this.state.scene;

    // "problem" this next line prevents rendering from both "top" and "bottom" calls
    const controls = new OrbitControls(camera, renderer.domElement);

    var animate = function () {
      // requestAnimationFrame(animate);
      // controls.update();
      render();
    }

    function render() {
      renderer.render(scene, camera)
    }

    animate();

    // "bottom" rendering call
    renderer.render(scene, camera);

  }

```

**renderCanvas** has always worked and continues to work when called. But when I swap **renderAnimatedCanvas** in its place, it will never render correctly when the control initialization line is not commented out. (Just below the “problem” comment.) If this line is commented out, the render will work either at the “top” call or at the “bottom” call. But when this “problem” line is left in, neither render call works, even the one at the “top”.

I figured to someone more experienced the error would be obvious. Thanks for any suggestions!

---

<div class="post-metadata">

**Author:** ![mjurczyk](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/mjurczyk/32/10995_2.png) [@mjurczyk](https://discourse.threejs.org/u/mjurczyk)\
**Post date:** [March 4, 2021, 4:27am UTC](https://discourse.threejs.org/t/orbitcontrols-in-react-kills-render/24034/2 "2021-03-04T04:27:31Z")

</div>

1. Could you explain why it’s necessary for you app to call `render` 5 times in 5 different configurations 🤔 ? Since `animate` is repeated on every frame, it shouldn’t be necessary to call `renderer.render` elsewhere (it will work, but it’ll just trigger an unnecessary re-render.)
2. Make sure the `renderAnimatedCanvas` method you shared isn’t called more than once by React - otherwise you’re recreating the render loop and controls (which at this point may be bound to window event handlers and reacting on the canvas that was removed during the component update.) Both the animation loop and the controls should, in most cases, be created only once.

---

<div class="post-metadata">

**Author:** ![NoahK](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/noahk/32/16776_2.png) [@NoahK](https://discourse.threejs.org/u/NoahK)\
**Post date:** [March 4, 2021, 4:31pm UTC](https://discourse.threejs.org/t/orbitcontrols-in-react-kills-render/24034/4 "2021-03-04T16:31:16Z")

</div>

I should have explained that I put the extra render statements in renderAnimatedCanvas() to try to isolate the problem. The essential method is like this:

```
renderAnimatedCanvas() {
    let renderer = this.state.renderer;
    let camera = this.state.camera;
    let scene = this.state.scene;

    // "problem" this next line prevents rendering called in animate function
    const controls = new OrbitControls(camera, renderer.domElement);

    var animate = function () {
      requestAnimationFrame(animate);
      controls.update();
      render();
    }

    function render() {
      renderer.render(scene, camera)
    }

    animate();
  }

```

Whenever “problem” line (and controls.update) are included, I can tell the scene is being loaded properly but nothing renders.

`renderAnimatedCanvas()` (or, previously, `renderCanvas()`) is called once at the end of every `componenentDidUpdate` lifecycle hook. This is called whenever an element of the component `state` changes. I know `componentDidUpdate` is called 5 or six times as the scene elements are loaded, but `renderAnimateCanvas` shouldn’t force additional `componentDidUpdate`'s

---

<div class="post-metadata">

**Author:** ![dubois](https://avatars.discourse-cdn.com/v4/letter/d/e9c0ed/32.png) [@dubois](https://discourse.threejs.org/u/dubois)\
**Post date:** [March 4, 2021, 8:11pm UTC](https://discourse.threejs.org/t/orbitcontrols-in-react-kills-render/24034/5 "2021-03-04T20:11:22Z")

</div>

So you kick off a rendering loop each time your react component changes? This is really hard to debug without at least seeing the entire react component. You should probably instantiate `OrbitControls` on something like `componentDidMount` not on update.

---

<div class="post-metadata">

**Author:** ![NoahK](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/noahk/32/16776_2.png) [@NoahK](https://discourse.threejs.org/u/NoahK)\
**Post date:** [March 4, 2021, 8:34pm UTC](https://discourse.threejs.org/t/orbitcontrols-in-react-kills-render/24034/7 "2021-03-04T20:34:00Z")

</div>

That makes sense to try. Can you think of anything wrong with making orbitControls part of the component state, so that renderAnimatedCanvas can access it like:

`let controls = this.state.orbitControls;`

?

---

<div class="post-metadata">

**Author:** ![NoahK](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/noahk/32/16776_2.png) [@NoahK](https://discourse.threejs.org/u/NoahK)\
**Post date:** [March 4, 2021, 9:10pm UTC](https://discourse.threejs.org/t/orbitcontrols-in-react-kills-render/24034/8 "2021-03-04T21:10:40Z")

</div>

@dubois: that worked with just a little fiddling! Thanks so much.

I had to reset the controls target to the scene center because for some reason it came in at 0,0,0. And my scene is too massive to orbit easily of course but I’ll have fun making that work.

For anyone else using React, this is what finally worked…

```
class Viewport extends Component {
  constructor(props) {
    super(props);

    this.state = {
      scene: new THREE.Scene(),
      camera: new THREE.PerspectiveCamera( 14, window.innerWidth / window.innerHeight, 10, 20000 ),
      renderer: new THREE.WebGLRenderer(),
      controls: null,
    };
  }

  componentDidMount() {
    this.setupCanvas();
    this.setState({ controls: new OrbitControls(this.state.camera, this.state.renderer.domElement) })
  }

  componentDidUpdate() {
    this.reviseCanvas();
    if (!this.props.loadingUnderway) {
        this.renderCanvas()
    } else this.renderAnimatedCanvas();
  }

```

and then…

```
renderAnimatedCanvas() {
    let renderer = this.state.renderer;
    let camera = this.state.camera;
    let scene = this.state.scene;
    let controls = this.state.controls;

    controls.target = new THREE.Vector3(this.props.sceneCenter.x, this.props.sceneCenter.y, this.props.sceneCenter.z);

    var animate = function () {
      requestAnimationFrame(animate);
      controls.update();
      console.log(controls)
      render();
    }

    function render() {
      renderer.render(scene, camera)
    }

    animate();
  }
```

---

<div class="post-metadata">

**Author:** ![mjurczyk](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/mjurczyk/32/10995_2.png) [@mjurczyk](https://discourse.threejs.org/u/mjurczyk)\
**Post date:** [March 4, 2021, 10:36pm UTC](https://discourse.threejs.org/t/orbitcontrols-in-react-kills-render/24034/9 "2021-03-04T22:36:06Z")

</div>

@NoahK having canvas / controls / render loop initialization in `componentDidUpdate` is a very risky move - it may work, but when it will stop working you’ll likely spend a week trying to figure out why - you can already see that for some reason `I had to reset the controls target to the scene center because [...] came in at 0,0,0` is happening, and it’s hard to figure out where and why.

As @dubois said - instantiate things that should be created only once (ie. renderer / camera / scene / controls / animation loop etc.) in enter the constructor (as private props, not as a state - state tends to update, and they shouldn’t), or in `componentDidMount`. In `componentDidUpdate` you can then update / toggle them as per need.

If that’s an option at the state of your project, you may also consider [react-three-fiber](https://github.com/pmndrs/react-three-fiber) - it’ll take care of this updates / disposal / refreshes automatically for you. 😅

---

<div class="post-metadata">

**Author:** ![dubois](https://avatars.discourse-cdn.com/v4/letter/d/e9c0ed/32.png) [@dubois](https://discourse.threejs.org/u/dubois)\
**Post date:** [March 5, 2021, 11:55pm UTC](https://discourse.threejs.org/t/orbitcontrols-in-react-kills-render/24034/10 "2021-03-05T23:55:59Z")

</div>

I don’t think that this is an antipattern. It’s not uncommon to store the reference to the renderer as context or in redux or something along those lines.

It would make sense to `setState({camera:someOtherCamera})` for example more than the renderer though. So to your point, it also wouldnt hurt to instantiate these on the component itself `this.camera`.

---

<div class="post-metadata">

**Author:** ![dubois](https://avatars.discourse-cdn.com/v4/letter/d/e9c0ed/32.png) [@dubois](https://discourse.threejs.org/u/dubois)\
**Post date:** [March 5, 2021, 11:57pm UTC](https://discourse.threejs.org/t/orbitcontrols-in-react-kills-render/24034/11 "2021-03-05T23:57:22Z")

</div>

The target thing though does seem risky, again there is a ton of code missing to figure out what was even supposed to happen to that camera and its controls in the first place.
