Animate presence not working in next js for exit animations only?

Viewed 3444

I'm trying to set an exit animation to my components in next js but I'm only able to give an initial animation.

Can someone tell me what is going wrong here??

Here is my sample code:

 <AnimatePresence >
        <motion.div key="modalBackground" className={styles['auth-modal-layout']} key="modalBackground" initial="hidden" animate="visible" variants={
                {
                    hidden:{
                        opacity:0
                    },
                    visible:{
                        opacity:1,
                        transition:{
                            duration:.4,
                        }
                    },
                }
            } >
            
            <motion.div key="modalForm" className={styles['auth-modal-form']} initial="hidden" exit="pageExit" animate="visible" exit="hidden"  variants={{
                hidden:{
                    translateY:100,
                    opacity:0
                },
                visible:{
                    translateY:0,
                    opacity:1,
                    transition:{
                        duration:.4
                    }
                },
                pageExit:{
                    opacity:0,
                    transition:{
                        when:"afterChildren",
                        duration:.4
                    }
                }
            }} >
                {modal()}
            </motion.div>
               
        </motion.div>
        </AnimatePresence> 

2 Answers

<AnimatePresence> needs to wrap the component that's being conditionally rendered. It can't be inside it.

You need to either move the <AnimatePresence> tag to a higher level or move your conditional logic into the component. Most likely you'd do the former, like so:

<AnimatePresence>
    {modalIsVisible && <ModalComponent />}
</AnimatePresence>

(In this example ModalComponent contains the code you show above).

Otherwise, you'd need to always render the component and pass in a prop to use to conditionally render the children. In your case (a modal window) I don't think that's what you want.

You do it like this, more examples here:

  <AnimatePresence>
     <motion.div
        // initial state opacity
        initial={{ opacity: 0 }}
        //animation of component appearence
        animate={{ opacity: 1 }}
        // how your element will appears f.e(duration in seconds)
        transition={{ delay: 0.5 }}
        // your exit animation
        exit={{ opacity: 0 }}
      >
       {your_content_here}
      </motion.div>
  </AnimatePresence>

If you are issuing some errors, it's not nextjs. Try to find issues inside code/lib of framer

Also you are typing inside your div (?ok 2 exit?):

initial="hidden" exit="pageExit" animate="visible" exit="hidden"

Check valid motion components. Always try to take examples from docs.

P.S. If you need to move "higher", you just wrap your parent component, or you can wrap code inside your _app.js. But this method means each page will load AnimatePresence code of framer lib.

function MyApp({ Component, pageProps }) {
  
  return (
    <AnimatePresence>
     <Component {...pageProps} />
    </AnimatePresence>
  )
  
}

MODIFICATION: I have checked AnimatePresence behavior it's not actually doing his work. I have checked how I did the same stuff. Here is an idea of how to do it, the code example is below.

//npm install this before: npm i react-intersection-observer
import { useInView } from "react-intersection-observer";

//in your hooks part, where you place hooks
const controls = useAnimation();
const [ref, inView] = useInView();
useEffect(() => {
  if (inView) {
     controls.start("visible");
  }
  else {
     controls.start("hidden");
  }
}, [controls, inView]);

//and the component, check how I did it (example)
<motion.div
 style={{marginTop: '1000px', marginBottom: '1000px'}}
 ref={ref}
 animate={controls}
 initial="hidden"
 transition={{ duration: 2 }}
 variants={{
     visible: { opacity: 1, scale: 1 },
     hidden: { opacity: 0, scale: 0 }
 }}

>
   <img src="https://super-monitoring.com/blog/wp-content/uploads/2020/03/framer.png"></img>
</motion.div>

For the many reasons I don't remember, I didn't use AnimationPresence. The problem with AnimationPresence it doesn't clearly "understands" where the user is at the moment on the page. I think it's why they added isVisible variable in framer examples. react-intersection-observer is working to detect where the user is. So sorry for the confusing info before the modification part.

P.S. Also check this

Related