Animate mapped items once when each is scrolled in view

1.2k Views Asked by At

I am having some trouble animating 3 div's using array.map. I would like to have each div animate once in view using framer motion.

The issue I am running into is that when trying to separately animate a div using inView, framer motion animates all 3 at once.

If I set inView ref={ref} on the parent Div, all 3 will animate together once the first is visible.

or

If I set ref={ref} on to the 3 mapped div's, all 3 will animate only once the 3rd and final div is in view.

I am trying to find a succinct way of individually animating into view Div's that have mapped data.

codesandbox Link for reference.

1

There are 1 best solutions below

0
On BEST ANSWER

You need to store separate state and controls for each div if you want them to behave separately. Easiest way is to make separate component:

const ProjectDiv = ({ onClick, item }) => {
  const controls = useAnimation();
  const [ref, inView] = useInView();

  useEffect(() => {
    if (inView) {
      controls.start('visible');
    }
  }, [controls, inView]);

  return (
    <motion.div
      ref={ref}
      className="project_card"
      onClick={onClick}
      animate={controls}
      initial="hidden"
      transition={{ duration: 1 }}
      variants={{
        visible: { opacity: 1, scale: 1 },
        hidden: { opacity: 0, scale: 0 }
      }}
    >
      <img src={item.image} alt="Project" />
      <h2>{item.title}</h2>
      <p>{item.description}</p>
    </motion.div>
  );
};

Codesandbox example