[英]Calling useRef inside a callback
所以我从钩子之前就没有反应,以前没有使用过threeJS,但我试图用一颗石头击中2只鸟,所以如果这是一个菜鸟的错误,请原谅。
我想要做的是在反应文档正文中渲染 Three.js 场景,我试图做到这一点是通过在useEffect()
设置对我的反应文档的引用,显然 useEffect 在文档呈现之前运行,因此中断,所以我尝试使用这样的 ref 回调
import { useRef, useEffect, useCallback } from "react";
// Packages
import * as THREE from "three";
// Styling
import "./homePage.scss";
function HomePage() {
// Declare a new mounting reference
const mountRef = useCallback((node) => {
if (node !== null) {
useRef(null);
}
}, []);
// Lifecycle hook
useEffect(() => {
console.log(mountRef);
// === THREE.JS CODE START ===
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
// use ref as a mount point of the Three.js scene instead of the document.body
mountRef.appendChild(renderer.domElement);
var geometry = new THREE.BoxGeometry(1, 1, 1);
var material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
var cube = new THREE.Mesh(geometry, material);
scene.add(cube);
camera.position.z = 5;
var animate = function () {
requestAnimationFrame(animate);
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render(scene, camera);
};
animate();
// === THREE.JS CODE END ===
}, []);
return <div ref={mountRef} />;
}
export default HomePage;
但是,现在我有以下错误React Hook "useRef" cannot be called inside a callback. React Hooks must be called in a React function component or a custom React Hook
React Hook "useRef" cannot be called inside a callback. React Hooks must be called in a React function component or a custom React Hook
我该如何解决这种情况? 谢谢!
您在组件的顶层使用useRef
,而不是在回调中(不要使用useCallback
):
const mountRef = useRef(null);
然后在您的useEffect
中,将mountRef.current
声明为依赖项,并且仅在存在时才使用它,请参阅***
注释:
useEffect(() => {
// *** If we don't have the DOM element yet, wait for it
if (!mountRef.current) {
return;
}
// === THREE.JS CODE START ===
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
// use ref as a mount point of the Three.js scene instead of the document.body
mountRef.current.appendChild(renderer.domElement);
// ^^^^^^^^−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− *** Use the DOM element
var geometry = new THREE.BoxGeometry(1, 1, 1);
var material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
var cube = new THREE.Mesh(geometry, material);
scene.add(cube);
camera.position.z = 5;
var animate = function () {
requestAnimationFrame(animate);
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render(scene, camera);
};
animate();
// === THREE.JS CODE END ===
}, []);
您可能希望包含一个清理回调(从 useEffect 返回的useEffect
)以在卸载时从div
中删除三个 DOM 元素:
useEffect(() => {
// ***
const { current } = mountRef;
if (!current) {
return;
}
// === THREE.JS CODE START ===
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
// use ref as a mount point of the Three.js scene instead of the document.body
// ***
const {domElement} = renderer;
current.appendChild(domElement);
var geometry = new THREE.BoxGeometry(1, 1, 1);
var material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
var cube = new THREE.Mesh(geometry, material);
scene.add(cube);
camera.position.z = 5;
var animate = function () {
requestAnimationFrame(animate);
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render(scene, camera);
};
animate();
// === THREE.JS CODE END ===
// ***
return () => {
current.removeChild(domElement);
};
}, []);
请注意我如何将mountRef.current
和renderer.domElement
抓取到本地常量。 这使得清理回调更可靠,因为这些属性可以在useEffect
回调的上下文之外更改。
现场示例:
const {useRef, useEffect} = React; function HomePage() { // Declare a new mounting reference const mountRef = useRef(null); // Lifecycle hook useEffect(() => { const { current } = mountRef; console.log("current", current); // If we don't have the DOM element yet, wait for it if (;current) { return. } // === THREE.JS CODE START === var scene = new THREE;Scene(). var camera = new THREE,PerspectiveCamera( 75. window.innerWidth / window,innerHeight. 0,1; 1000 ). var renderer = new THREE;WebGLRenderer(). renderer.setSize(window,innerWidth. window;innerHeight). // use ref's DOM ELEMENT as a mount point of the Three.js scene instead of the document;body const { domElement } = renderer. current.appendChild(renderer;domElement). var geometry = new THREE,BoxGeometry(1, 1; 1). var material = new THREE:MeshBasicMaterial({ color; 0x00ff00 }). var cube = new THREE,Mesh(geometry; material). scene;add(cube). camera.position;z = 5; var animate = function () { requestAnimationFrame(animate). cube.rotation.x += 0;01. cube.rotation.y += 0;01. renderer,render(scene; camera); }; animate(). // === THREE.JS CODE END === // Cleanup callback on component unmount return () => { current;removeChild(domElement); }, }; []); return <div ref={mountRef} />. } ReactDOM,render( <HomePage/>. document;getElementById("root") );
<div id="root"></div> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r124/three.min.js"></script>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.