Search code examples
reactjsanimationframer-motion

Having visual bug when trying to make carousel with Framer Motion


I'm trying to make a carousel using Framer Motion in React, but I am getting a visual bug. The previous component isn't being unmounted before the new one is, and I am getting a weird effect.this Gyazo

This is the component handling everything:

const ProjectList = props => {

  const [page, setPage] = useState(0);

  const projects = [
    <Project 
      name="Example"
      desc="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Libero nunc consequat interdum varius sit amet."
      image={require("../img/office.jpg")}
    />,
    <Project 
      name="Example2"
      desc="Another example. This one does nothing too. What a suprise!"
      image={require("../img/office.jpg")}
    />
  ]

  const paginate = (newPage) => {
    if(newPage < 0) {
      setPage(projects.length - 1)  
    } else if (newPage > projects.length - 1) {
      setPage(0);
    } else {
      setPage(newPage);
    }
  }

  return (
    
    <div className="project-list">
      <AnimatePresence>
        <motion.button 
          key="previous"
          onClick={() => paginate(page-1)}
          className="carousel-btn"
          whileHover={{scale: 1.5, transition: {duration: 0.5}}}
        >
          <ArrowBackIosIcon/>
        </motion.button>
        <motion.div
          key={page}
          initial={{opacity: 0}}
          animate={{opacity: 1}}
          exit={{opacity: 0}}
        >
          {projects[page]}
        </motion.div>

        <motion.button 
          key="next" 
          onClick={() => paginate(page+1)}
          className="carousel-btn" 
          whileHover={{scale: 1.5, transition: {duration: 0.5}}}>
          <ArrowForwardIosIcon/>
        </motion.button>
      </AnimatePresence>
    </div>
  );

};

I'm not sure how to use libraries like framer-motion in the snippet tool, so here's a stripped down version on CodeSandbox

Edit priceless-sammet-9w1t3


Solution

  • If you want one component to finish its unmount (exit) animation before the mount animation of the next one starts, you’ll have to switch on AnimatePresence’s exitBeforeEnter.

    https://www.framer.com/api/motion/animate-presence/#animatepresenceprops.exitbeforeenter

    Don’t know about that visual bug, because it’s not visible in the CodeSandbox example. But it might be because the component is (momentarily) removed from the DOM, which causes things to reorder. A solution might be to only put the motion.div holding the image inside AnimatePresence, as I did here:

    https://codesandbox.io/s/carousel-with-framer-motion-stackoverflow-lmrik?file=/src/components/ProjectList.js