我试图以动态方式访问引用,但在使用Ref时收到错误"无效的钩子调用.钩子只能在函数组件的主体内调用".这里:

const [subsistemaPlanetario, setSubsistemaPlanetario] = useState([]);
const planetRefs = useRef({});

useEffect(() => {
  async function fetchSubsistemaPlanetario() {
    try {
      const fetchedSubsistemaPlanetario = await getSubsistemaPlanetario();
      setSubsistemaPlanetario(fetchedSubsistemaPlanetario);

      fetchedSubsistemaPlanetario.forEach((planeta) => {
        const camelCaseSlug = planeta.padre.slug.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
        planetRefs.current[camelCaseSlug] = useRef(); // <------THIS LINE DROP AN ERROR
      });
    } catch (error) {
      console.error(error);
    }
  }

  fetchSubsistemaPlanetario();
}, []);

整个组件:

import {useFrame} from '@react-three/fiber';
import React, {useRef, useEffect, useState} from 'react';
import {Planet} from './Planet.jsx';
import {Satellite} from './Satellite.jsx';
import {Orbiter} from './utils/Orbiter.js';
import {calculateOrbitalPeriod} from './utils/calculateOrbitalPeriod.js';

import {getSubsistemaPlanetario} from './utils/getSubsistemaPlanetario.js';

export const SubsistemaPlanetario = function SubsistemaPlanetario(props) {
  let running = true;
  let stopRunning = () => (running = false);
  let startRunning = () => (running = true);

  const [subsistemaPlanetario, setSubsistemaPlanetario] = useState([]);
  const planetRefs = useRef({});

  useEffect(() => {
    // Obtener el subsistema planetario cuando el componente se monta
    async function fetchSubsistemaPlanetario() {
      try {
        const fetchedSubsistemaPlanetario = await getSubsistemaPlanetario();
        
        setSubsistemaPlanetario(fetchedSubsistemaPlanetario);

        fetchedSubsistemaPlanetario.forEach((planeta) => {
          const camelCaseSlug = planeta.padre.slug.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());

          planetRefs.current[camelCaseSlug] = useRef();
          console.log(planetRefs);
        });
      } catch (error) {
        console.error(error);
      }
    }

    fetchSubsistemaPlanetario();
  }, []);

  return (
    <>
      {subsistemaPlanetario.map((planetaPadre, index) => (
        <Planet
          key={index}
          scale={0.5}
          ref={planetRefs.current[index]}
          stopRunning={stopRunning}
          startRunning={startRunning}
          textureType="haumea"
          linkTo="areas"
          linkToLabel="Areas"
        />
      ))}
    </>
  );
};

行星组件

import {forwardRef, useRef, useEffect, useContext, useState} from 'react';
import PropTypes from 'prop-types';
import {useTexture} from '@react-three/drei';
import {useFrame} from '@react-three/fiber';
import barba from '@barba/core';
import {solapaContentAbrir, solapaContentCerrar} from './utils/Solapa.js';
import {planets} from './utils/arrayTexturas.js';

// Define un objeto que mapea los tipos de textura a las rutas de los archivos de textura.
const textureMap = {};

for (const planet of planets) {
  textureMap[planet] = `./app/themes/sage/resources/scripts/cosmos/components/textures/${planet}-512.jpg`;
}

export const Planet = forwardRef(function Planet(props, ref) {
  // Obtén la ruta de la textura según el tipo especificado en props.textureType.
  const texturePath = textureMap[props.textureType] || textureMap.sand;
  const texture = useTexture(texturePath);

  let rotationX = Math.random();
  let rotationY = Math.random();

  useFrame((state, delta) => {
    ref.current.rotation.x += rotationX * delta;
    ref.current.rotation.y += rotationY * delta;
  });

  return (
    <mesh
      {...props}
      ref={ref}
      castShadow
      receiveShadow
      onPointerEnter={(event) => {
        props.stopRunning();
        document.body.style.cursor = 'pointer';
        solapaContentAbrir('Sección', props.linkToLabel);
        event.stopPropagation();
      }}
      onPointerLeave={(event) => {
        props.startRunning();
        document.body.style.cursor = 'default';
        solapaContentCerrar();
        event.stopPropagation();
      }}
      onClick={(event) => {
        barba.go(props.linkTo);
      }}
    >
      <sphereGeometry />
      <meshStandardMaterial map={texture} />
    </mesh>
  );
});

Planet.propTypes = {
  stopRunning: PropTypes.func,
  startRunning: PropTypes.func,
  textureType: PropTypes.oneOf(['haumea', 'mars', 'neptune', 'venus', 'mercury', 'jupiter', 'saturn']),
  userData: PropTypes.object,
  radius: PropTypes.number,
  linkTo: PropTypes.string,
  linkToLabel: PropTypes.string,
};

如果有任何帮助,我很感激.

推荐答案

正如这里已经提到的,您不能在任何形式的控制流中使用钩子. 所以没有if,else,for,while,forEach,callback,...

您可以使用带有回调的ref={},如下所示:

<Planet
          key={index}
          ref={(ref) => {planetRefs[index] = ref}}

但除此之外,没有办法让裁判像你一样拥有他们.

编辑: 我仍然不确定你在这里试图达到什么目的,但没有必要引用行星本身之外的行星. (老实说,可能根本不需要裁判) 您可以简单地更新Planet中的旋转并完成它.

export const Planet = function Planet(props, ref) {
  // ...

  const ref = useRef();
  let rotationX = Math.random();
  let rotationY = Math.random();

  useFrame((state, delta) => {
    ref.current.rotation.x += rotationX * delta;
    ref.current.rotation.y += rotationY * delta;
  });

  return (
    <mesh
      {...props}
      ref={ref}
      // ...
    >
      // ...
  );
};

// ...

或者,如果外部确实需要引用,在我看来很少这样做,创建一个数组/对象并将其传递给Planet组件.

const planets = useRef({});

// ...

planets.forEach((planet) => {
  return <Planet key={planet.slug} planets={planets.current} ... />
});


function Planet(props) {
  const ref = useRef();
  useEffect(() => {
    // Add it to the list of planets when component is rendered
    props.planets[props.slug] = ref;
  }, () => {
    // Remove when no longer needed
    props.planets[props.slug] = undefined;
  });

  // ...
}

您可以使用以下命令访问它

  planets.current[slug].current

Reactjs相关问答推荐

InfiniteScroll持续获取数据,直到超过最大更新深度

包装组件可以避免子组件重新渲染.?

如何在重新图表中更改悬停时的条形填充 colored颜色 ?

导致useState中断的中断模式

Reaction Ploly:如何在多个子情节中共享zoom 状态

禁止直接访问Next.js中的页面,同时允许从应用程序内部访问

Next.js Next-Auth登录函数重定向到http://localhost:3000/api/auth/error

当useEffect和onClick处理程序都调用useCallback函数时,有没有办法对useEffect产生额外的影响?

在 Next13 中将 props 传递给 onClick 从服务器到客户端组件

ReactJS 共享上下文

如何优化 React 应用程序的性能?

无法使用 MongoDB Atlas 和 Next.js 删除正确的帖子

无法从子组件传递数据到父组件

React 组件列表中的第一个计时器正在获取值 NaN

当我在 React Router Dom 中使用两个参数并直接在页面上导航时,数据获取没有发生

我可以更改 styled() 中的响应吗? (MUI v5)

如何从其他组件访问 useQuery refetch 方法?

如何在 React 中单击鼠标的位置动态添加 div?

交换键仍然引入了 fresh 的 DOM 元素

在 React 中使用使用状态挂钩合并两个数组