簡體   English   中英

在回調中調用 useRef

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

您不能在回調中定義掛鈎,請參閱 掛鈎規則

要獲取div引用,您只需要提供來自useRef的引用,根本不需要useCallback ,請參閱文檔示例

const mountRef = useRef(null);
<div ref={mountRef} />

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM