[英]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.