事件处理程序

时间:2018-02-10 16:35:30

标签: javascript reactjs redux react-redux this

我们正在构建一个React-Redux Web应用程序,它将显示多个三个JS场景。这些场景成对出现,每对都将同步缩放。为方便起见,我们将相机数据存储在Redux商店中。

这是我们的React类(深呼吸,对于一个SO问题有点长),它使用react-three-renderer来生成三个JS对象:

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { Vector3 } from 'three';
import React3 from 'react-three-renderer';
import ReferenceGrid from './ReferenceGridVisual';
import ResourceGroup from './resourceGroups/ResourceGroup';
import { initializeRayCastScene } from './viewportMath/RayCastScene';
import zoomCamera from './viewportMath/CameraZoom';
import { registerCamera, zoom } from './actions/cameraActions';
import { InitThreeJsDomEvents, UpdateDomCamera } from './domUtility/ThreeJSDom';

class ThreeJsScene extends Component {
  constructor(props) {
    super(props);

    this.ZoomAmount = 150;
    this.ZoomMaxCap = 1000;
    this.ZoomMinCap = 6;
    this.zoomPadding = 10;
    this.minimumZoom = 45;
  }

  componentWillMount() {
    initializeRayCastScene();

    this.props.registerCamera(this.props.sceneName);
  }

  componentDidMount() {
    // eslint-disable-next-line no-underscore-dangle
    InitThreeJsDomEvents(this.camera, this.canvas._canvas);
  }

  onWheel = (event) => {
    // eslint-disable-next-line
    this.zoom(event.clientX, event.clientY, event.deltaY);
  }

  setCameraRef = (camera) => {
    UpdateDomCamera(camera);
    this.camera = camera;
  }

  zoom(screenPosX, screenPosY, zoomAmount) {
    const size = {
      width: this.props.width,
      height: this.props.height,
    };
    const result = zoomCamera(screenPosX, screenPosY, zoomAmount, this.camera.position,
      size, this.props.distance, this.camera, this.props.cameraType, this.ZoomMaxCap,
      this.ZoomMinCap);
    this.ZoomAmount = (result.ZoomAmount) ? result.ZoomAmount : this.ZoomAmount;
    this.props.zoom(this.props.sceneName, result.distanceChangeFactor, result.newCameraPosition);
  }

  render() {
    let position;
    if (this.props.cameraPosition != null) {
      position = new Vector3(
        this.props.cameraPosition.x,
        this.props.cameraPosition.y,
        this.props.cameraPosition.z
      );
    } else {
      position = new Vector3();
    }
    const left = -this.props.width / 2;
    const right = this.props.width / 2;
    const top = this.props.height / 2;
    const bottom = -this.props.height / 2;

    return (
      <div
        style={{ lineHeight: '0' }}
        onWheel={this.onWheel}
      >
        <React3
          width={this.props.width}
          height={this.props.height}
          mainCamera="camera"
          antialias
          pixelRatio={1}
          ref={(canvas) => { this.canvas = canvas; }}
        >
          <scene ref={(scene) => { this.scene = scene; }}>
            <orthographicCamera
              name="camera"
              left={left}
              right={right}
              top={top}
              bottom={bottom}
              near={0.01}
              far={1400}
              position={position}
              ref={this.setCameraRef}
            />
            <ambientLight
              color={0xaaaaaa}
            />
            <directionalLight
              color={0xaaaaaa}
              intensity={1.1}
              position={new Vector3(3, 4, 10)}
              lookAt={new Vector3(0, 0, 0)}
            />
            <ReferenceGrid xActive yActive zActive={false} store={this.props.store} />
            <ResourceGroup store={this.props.store}>
              {this.props.children}
            </ResourceGroup>
          </scene>
        </React3>
      </div>
    );
  }
}

const mapStateToProps = (state, ownProps) => {
  const ownCamera = state.cameras.get(ownProps.sceneName);
  if (ownCamera == null) {
    console.log('own camera null');
    return { cameraAvailable: false };
  }
  console.log('has own camera');
  const cameraPosition = ownCamera.position;
  const cameraType = ownCamera.type;
  const distance = ownCamera.distance;
  return {
    cameraAvailable: true,
    cameraPosition,
    cameraType,
    distance,
  };
};

const mapDispatchToProps = dispatch => ({
  registerCamera: (cameraName) => {
    dispatch(registerCamera(cameraName));
  },
  zoom: (cameraName, factor, newCameraPosition) => {
    dispatch(zoom(cameraName, factor, newCameraPosition));
  },
});

export default connect(mapStateToProps, mapDispatchToProps)(ThreeJsScene);

此外,作为参考,以下是动作创建者:

export const registerCamera = cameraName => (dispatch) => {
  dispatch({ type: 'REGISTER_CAMERA', newCameraName: cameraName });
};

export const zoom = (cameraName, factor, newCameraPosition) => (dispatch, getState) => {
  const state = getState();
  const zoomFactor = state.cameras.get(cameraName).distance * (1 - factor);
  dispatch({ type: 'CAMERA_ZOOM', cameraName, factor: zoomFactor, newCameraPosition });
};

还原剂:

import { Map } from 'immutable';

const defaultCameraProperties = {
  distance: 150,
  type: 'orthogonal',
  position: { x: 0, y: 10, z: 50 },
  rotation: { x: 0, y: 0, z: 0, w: 1 },
};

const initialState = Map();

export default (state = initialState, action) => {
  switch (action.type) {
    case 'REGISTER_CAMERA': {
      const newCamera = {
        ...defaultCameraProperties,
        ...action.newCameraProperties,
      };
      return state.set(action.newCameraName, newCamera);
    }

    case 'CAMERA_ZOOM': {
      const updatedDistance = action.factor;
      const updatedCameraPosition = {
        ...state.get(action.cameraName).position,
        ...action.newCameraPosition,
      };
      const updatedCamera = {
        ...state.get(action.cameraName),
        position: updatedCameraPosition,
        distance: updatedDistance,
      };
      return state.set(action.cameraName, updatedCamera);
    }

    default: {
      return state;
    }
  }
};

挑战在React类的zoom函数中,React props不是我所期望的,因此缩放失败。以下是我理解的相关事件序列的摘要:

    调用
  1. componentWillMount,调度REGISTER_CAMERA方法。 (我们这样做而不是在商店中默认拥有相机数据,因为这些场景是动态生成的 - 它们没有静态数量。)
  2. 调用React render方法。
  3. 再次调用React render方法,因为REGISTER_CAMERA操作现在已经修改了商店,我们有了新道具 - 相机相关道具现在可用。
  4. 我用鼠标滚轮触发变焦。 onWheel处理程序调用{​​{1}}函数,但该方法中的断点显示相机相关道具(如zoom - 是this.props.cameraType。 React道具显示在2中。(undefined进行一些计算。由于这些属性不可用,缩放失败。)
  5. 我无法弄清楚为什么会这样。我的怀疑是我误解了zoomCamera上下文绑定到缩放方法的内容。

    简而言之,我的问题是为什么我的this不是最新版本,如何才能将更新版本提供给props函数?

1 个答案:

答案 0 :(得分:0)

原来这是热模块重新加载的错误。运行我们的构建冷却不会出现问题。