I’m trying to assing refs dinamically, but I get the error "Invalid hook call. Hooks can only be called inside of the body of a function component" when useRef. Here:
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();
}, []);
ENTIRE COMPONENT:
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"
/>
))}
</>
);
};
Any help appreciated.
2
Answers
Not sure exactly what you are trying to achieve here.
will do nothing since
planetRefs.current
is an empty object and will remain as an empty object since you are not assigning any value to it.will also do nothing since you can’t use react hooks inside a function that is not a react component.
Possible solution
I think you should be using a callback ref instead, to get the access to the rendered elements:
Note: Remember to wrap your
Planet
component withforwardRef
.Edit:
You can remove the
planetRefs.current[camelCaseSlug] = useRef();
part completely. If you prefer to keep therefs
in theplanetRefs
as slugs, just modify the callback ref a bit:You are calling a hook conditionally for your component
https://legacy.reactjs.org/docs/hooks-rules.html