我正在做一个有趣的项目,以帮助提高我对 ReactJS 和 ThreeJS 的认识和理解,但是遇到了将数据从父类传递到子类中的函数的问题。现在我的项目如下所示: App.js
import React, {Component} from 'react';
import {Globe, Building, BuildingBody} from './components';
import styles from './App.module.css';
import { fetchData } from './assets/api';
class App extends Component {
state = {
data: {},
state: '',
isMounted: true,
}
componentDidMount() {
const fetchedData = fetchData();
this.setState({ data: fetchedData});
}
handleStateChange = (state) => {
const fetchedData = fetchData(state);
this.setState({data: fetchedData, state: state})
}
render() {
const { data, state, isMounted=true } = this.state;
return (
<div className={styles.container}>
<div className={styles.dataContainer}>
<Building handleStateChange={this.handleStateChange.bind(this)}/>
<BuildingBody data = {data} state={state} />
</div>
<Globe data = {data} state={state}/>
</div>
);
}
}
export default App;
我的 ThreeJS 部分如下所示: Globe.jsx
import React, { Component } from 'react';
import * as THREE from 'three';
import {OrbitControls} from 'three/examples/jsm/controls/OrbitControls';
import earthmap from '../../assets/images/earthmap4k.jpg';
import earthbump from '../../assets/images/earthbump4k.jpg';
import earthspec from '../../assets/images/earthspec4k.jpg';
import particle from '../../assets/images/particle.jpg';
import clouds from '../../assets/images/earthhiresclouds4K.jpg';
class Globe extends Component {
constructor(props) {
super (props);
this.state = {
state: props.state,
data: props.data
}
}
componentDidMount() {
console.log(this.state.data)
console.log(this.state.state)
this.createScene();
this.addSceneObjects();
this.startAnimation();
window.addEventListener('resize', this.handleWindowResize);
}
componentWillUnmount() {
window.removeEventListener('resize', this.handleWindowResize);
window.cancelAnimationFrame(this.requestID);
this.controls.dispose();
}
createScene = () => {
this.scene = new THREE.Scene();
this.camera = new THREE.PerspectiveCamera( 75, 720 / 480, 0.1, 1000 );
this.controls = new OrbitControls(this.camera, this.mount);
this.controls.enableZoom = false
this.renderer = new THREE.WebGLRenderer({ antialiasing: true });
this.renderer.setSize( 720, 480 );
this.mount.appendChild( this.renderer.domElement );
this.camera.position.z = 20;
};
addSceneObjects = () => {
this.addLight();
this.addEarth();
this.addCoord();
};
addLight = () => {
const lights = [];
lights[0] = new THREE.PointLight(0xffffff, .3, 0);
lights[1] = new THREE.PointLight(0xffffff, .4, 0);
lights[2] = new THREE.PointLight(0xffffff, .7, 0);
lights[3] = new THREE.AmbientLight( 0x706570 );
lights[0].position.set(0, 200, 0);
lights[1].position.set(200, 100, 400);
lights[2].position.set(-200, -200, -50);
this.scene.add(lights[0]);
this.scene.add(lights[1]);
this.scene.add(lights[2]);
this.scene.add(lights[3]);
};
addEarth = () => {
const earthMap = new THREE.TextureLoader().load( earthmap );
const earthBumpMap = new THREE.TextureLoader().load( earthbump);
const earthSpecMap = new THREE.TextureLoader().load( earthspec);
const earthGeometry = new THREE.SphereGeometry( 10, 32, 32 );
const earthMaterial = new THREE.MeshPhongMaterial({
map: earthMap,
bumpMap: earthBumpMap,
bumpScale: 0.10,
specularMap: earthSpecMap,
specular: new THREE.Color('grey')
});
this.earthSphere = new THREE.Mesh( earthGeometry, earthMaterial );
this.scene.add( this.earthSphere );
const earthGeo = new THREE.SphereGeometry(10, 36, 36 );
const cloudsTexture = THREE.ImageUtils.loadTexture( clouds );
const materialClouds = new THREE.MeshLambertMaterial({
color: 0xffffff,
map: cloudsTexture,
transparent:true,
opacity:0.4
});
this.earthClouds = new THREE.Mesh( earthGeo, materialClouds );
this.earthClouds.scale.set( 1.015, 1.015, 1.015 );
this.earthSphere.add( this.earthClouds );
};
addCoord = () => {
this.particleMat = new THREE.PointsMaterial({
color: 'rgb(255, 255, 255)',
size: 0.25,
//map: new THREE.TextureLoader().load(particle),
//transparent: true,
//blending: THREE.AdditiveBlending,
//depthWrite: false
});
this.particleGeo = new THREE.SphereGeometry(10, 64, 64);
this.particleGeo.vertices.forEach(function(vertex) {
const lat = 31.688372;
const lon = -106.405023;
const radius = 10;
const phi = (90-lat)*(Math.PI/180);
const theta = (lon+180)*(Math.PI/180);
vertex.x = -((radius) * Math.sin(phi)*Math.cos(theta));
vertex.z = ((radius) * Math.sin(phi)*Math.sin(theta));
vertex.y = ((radius) * Math.cos(phi));
});
this.particleSystem = new THREE.Points(
this.particleGeo,
this.particleMat
);
this.particleSystem.name = 'particleSystem';
this.earthClouds.add(this.particleSystem);
};
startAnimation = () => {
this.earthSphere.rotation.y += 0.0009;
//this.earthClouds.rotation.y += 0.001;
this.requestID = window.requestAnimationFrame(this.startAnimation);
//requestAnimationFrame(this.startAnimation);
this.controls.update();
this.renderer.render( this.scene, this.camera );
};
handleWindowResize = () => {
const width = this.mount.innerWidth;
const height = this.mount.innerHeight;
this.renderer.setSize(width, height);
this.camera.aspect = width / height;
this.camera.updateProjectionMatrix();
};
render() {
console.log(this.props.data)
console.log(this.props.state)
return (
<>
<div ref={ref => (this.mount = ref)} data = {this.props.data} state = {this.props.state}>
</div>
</>
)
}
}
export default Globe;
App.js中的数据确实会传递到render()
我的Globe.jsx的函数中。但是,我想获取该数据并将其传递到Globe.jsx主体中,以便使用
this.particleGeo.vertices.forEach(function(vertex) {
const lat = **INSERT DATA.latitude**;
const lon = **INSERT DATA.longitude**;
const radius = 10;
const phi = (90-lat)*(Math.PI/180);
const theta = (lon+180)*(Math.PI/180);
vertex.x = -((radius) * Math.sin(phi)*Math.cos(theta));
vertex.z = ((radius) * Math.sin(phi)*Math.sin(theta));
vertex.y = ((radius) * Math.cos(phi));
});
但我目前在完成这项任务时迷失了方向。我知道可以访问作为函数的组件中的数据,但是当尝试将我的Globe.jsx转换为函数而不是类时,我的代码会中断(在更改this.state
为变量/let/等之后)。如果大家能帮帮我,我将不胜感激。