reactjsframer-motioninview

Animate mapped items once when each is scrolled in view


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.


Solution

  • 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