React-Three-Renderer在componentDidUpdate(包括MVCE)中引用不是最新的

Sco*_*y H 8 javascript lifecycle refs reactjs

我正在使用react-three-renderer(npm,github)来构建一个包含three.js的场景.

我有一个问题,我已经归结为一个MVCE.Refs没有按照我期望的顺序更新.首先,这是要查看的主要代码:

var React = require('react');
var React3 = require('react-three-renderer');
var THREE = require('three');
var ReactDOM = require('react-dom');

class Simple extends React.Component {
  constructor(props, context) {
    super(props, context);

    // construct the position vector here, because if we use 'new' within render,
    // React will think that things have changed when they have not.
    this.cameraPosition = new THREE.Vector3(0, 0, 5);

    this.state = {
      shape: 'box'
    };

    this.toggleShape = this.toggleShape.bind(this);
  }

  toggleShape() {
    if(this.state.shape === 'box') {
      this.setState({ shape: 'circle' });
    } else {
      this.setState({ shape: 'box' });
    }
  }

  renderShape() {
    if(this.state.shape === 'box') {
      return <mesh>
        <boxGeometry
          width={1}
          height={1}
          depth={1}
          name='box'
          ref={
            (shape) => {
              this.shape = shape;
              console.log('box ref ' + shape);
            }
          }
        />
        <meshBasicMaterial
          color={0x00ff00}
        />
      </mesh>;
    } else {
      return <mesh>
        <circleGeometry
          radius={2}
          segments={50}
          name='circle'
          ref={
            (shape) => {
              this.shape = shape;
              console.log('circle ref ' + shape);
            }
          }
        />
        <meshBasicMaterial
          color={0x0000ff}
        />
      </mesh>
    }
  }

  componentDidUpdate() {
    console.log('componentDidUpdate: the active shape is ' + this.shape.name);
  }

  render() {
    const width = window.innerWidth; // canvas width
    const height = window.innerHeight; // canvas height

    var position = new THREE.Vector3(0, 0, 10);
    var scale = new THREE.Vector3(100,50,1);

    var shape = this.renderShape();

    return (<div>
        <button onClick={this.toggleShape}>Toggle Shape</button>
        <React3
          mainCamera="camera"
          width={width}
          height={height}
          onAnimate={this._onAnimate}>
          <scene>
            <perspectiveCamera
              name="camera"
              fov={75}
              aspect={width / height}
              near={0.1}
              far={1000}
              position={this.cameraPosition}/>
            {shape}
          </scene>
        </React3>
    </div>);
  }
}

ReactDOM.render(<Simple/>, document.querySelector('.root-anchor'));
Run Code Online (Sandbox Code Playgroud)

这将呈现一个带有绿色框的基本场景,在react-three-renderer的github登陆页面上示例的一个分支.左上角的按钮将场景中的形状切换为蓝色圆圈,如果再次单击,则返回绿色框.我正在做一些登录ref回调和登录componentDidUpdate.这就是我遇到的问题的核心所在.在第一次单击切换按钮后,我希望形状的参考指向圆.但正如您从日志记录中看到的那样,在componentDidUpdateref中仍然指向框:

componentDidUpdate:活动形状为框

在此之后记录行显示引用了回调

box ref null [React在旧的ref上调用null以防止内存泄漏]

circle ref [object Object]

您可以删除断点以验证和检查.我希望在我们进入之前发生这两件事componentDidUpdate,但正如你所看到的,它正在发生相反的情况.为什么是这样?是否有反应,三渲染一个潜在的问题(如果是这样,你可以诊断呢?),或者我误解反应裁判?

MVCE在此github存储库中可用.下载,运行npm install并打开_dev/public/home.html.

提前致谢.

vij*_*yst 2

我检查了react-三渲染器中的源代码。在 lib/React3.jsx 中,有一个两阶段渲染。

componentDidMount() {
    this.react3Renderer = new React3Renderer();
    this._render();
  }

  componentDidUpdate() {
    this._render();
  }
Run Code Online (Sandbox Code Playgroud)

_render 方法似乎是加载子项的方法 - Three 中的网格对象。

_render() {
    const canvas = this._canvas;

    const propsToClone = { ...this.props };

    delete propsToClone.canvasStyle;

    this.react3Renderer.render(
      <react3
        {...propsToClone}
        onRecreateCanvas={this._onRecreateCanvas}
      >
        {this.props.children}
      </react3>, canvas);
  }
Run Code Online (Sandbox Code Playgroud)

render 方法绘制画布,但不会填充子级或调用 Three。

  render() {
    const {
      canvasKey,
    } = this.state;

    return (<canvas
      ref={this._canvasRef}
      key={canvasKey}
      width={this.props.width}
      height={this.props.height}
      style={{
        ...this.props.canvasStyle,
        width: this.props.width,
        height: this.props.height,
      }}
    />);
  }
Run Code Online (Sandbox Code Playgroud)

总结一下,顺序是这样的:

  1. 调用应用程序组件渲染。
  2. 这会渲染出绘制画布的react- Three-renderer。
  3. 调用App组件的componentDidUpdate。
  4. 调用react-two-renderer的componentDidUpdate。
  5. 这会调用 _render 方法。
  6. _render 方法通过将 props.children(网格对象)传递给 Three 库来更新画布。
  7. 当网格对象被安装时,相应的引用被调用。

这解释了您在控制台语句中观察到的内容。