繁体   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