While watching a YouTube tutorial by web animations expert Olivier Larose, I noticed something unusual and potentially against the conventional rules of React hooks.
In the video, it appears that he's calling the useTransform()
hook directly inside JSX, such as within a <p>
tag — essentially inside the return
statement of a component.
From my understanding, React hooks must be called at the top level of a functional component, not within the return
or inside conditionals or loops.
Here's a simplified version of what I saw:
// Example Code
function AnimationExample (){
return (<div>
<h3>Heading</h3>
<p>
{
word.split("").map((letter, i) => {
--> const y = useTransform(scrollYProgress,[0, 1],[0, Math.floor(Math.random() * -75) - 25]);
return (
<motion.span style={{ top: y }} key={`l_${i}`}>
{letter}
</motion.span>
);
})
}
</p>
</div>)};
Since the hook is executed in the same place in the function flow every time (so long as word
remains unchanged), this will probably work.
But it is terrible, terrible practice. Hooks are something of a hack; wrapping a hack inside a hack is just begging for trouble in the long (and even medium) run.
Re-write it as:
const DisplayWord: FC<{ letter: string }> = ({ letter }) => {
const rnd = useMemo(() => Math.floor(Math.random() * -75) - 25, []);
const top = useTransform(scrollYProgress, [0, 1], [0, rnd]);
return (
<motion.span style={{ top }}>
{letter}
</motion.span>
);
};
function AnimationExample() {
return (
<div>
<h3>Heading</h3>
<p>
{word.split("").map((letter, i) => (
<DisplayWord key={`l_${i}`} letter={letter} />
))}
</p>
</div>
);
}