React: Rendered more hooks than during the previous render? React-spring



I’ve seen similar questions on SO about this error, but I haven’t been able to fix my problem below.

The situation

The code at this link works:

https://codesandbox.io/s/frosty-water-118xp?file=/src/App.js

However, what I don’t like about it is that I need to repeat myself in the ‘slides’ array, by outlining the slide structure again and again (as you can see from lines 78 to 131).

I’m trying to replace that approach with a function that will generate the slide with the necessary information on demand. For example, I would keep all of the slide information in an array like this:

const slideInformation = [
  {
    src: Image1,
    bigText: "ONE",
    littleText: "one",
  },
  {
    src: Image2,
    bigText: "TWO",
    littleText: "two",
  },
  {
    src: Image3,
    bigText: "THREE",
    littleText: "three",
  },
];

…and pass that information when needed to the return statement of the transition function on line 171 like this:

{transitions((style, i) => {
   const Slide = SlideFactory(style, slideInformation[i]);
   return <Slide />;
})}

The problem

However, when I do that I get the following error when the first slide changes to the second: “Error: Rendered more hooks than during the previous render.”

Why doesn’t this work?

You can see my (not-working) attempt with this solution here:

https://codesandbox.io/s/adoring-mountain-bgd07?file=/src/App.js

Answer

Instead of having SlideFactory be a helper function that you call while rendering App, turn it into a component of its own. With the helper function version, you change how many times you call SlideFactory from one render to the next, which in turn changes how many hooks App calls, violating the rules of hooks.

But if you do it as a component, then it’s perfectly fine to change how many components App returns, and when those components render, they’ll only call one hook each.

// You should name this using the `use` convention so that it's clear (to both
//   humans and lint tools) that it needs to follow the rules of hooks
const useZoomSpring = () => {
  return useSpring({
    from: { number: 1.0 },
    to: { number: 1.1 },
    config: { duration: duration },
  });
};

// It now expects a props object, not two separate parameters
const SlideFactory = ({ style, index }) => {
  const zoom = useZoomSpring();
  return (
    <SlideContainer style={style}>
      <ImageContainer
        src={slideInformation[index].src}
        style={{
          ...style,
          scale: zoom.number.to((n) => n),
        }}
      />
      <BigText>{slideInformation[index].bigText}</BigText>
      <LittleText>{slideInformation[index].littleText}</LittleText>
    </SlideContainer>
  );
}

// ...
{transitions((style, i) => {
  // creating a JSX element, not calling a function
  return <SlideFactory style={style} index={i}/>
})}


Source: stackoverflow