Search code examples
reactjsintersection-observerframer-motion

How to use multiple 'useInView' hooks in the same react component?


I'm working on a react project and trying to animate and show the divs once they're in the view. I'm using the useInView hook from 'react-intersection-observer' to determine if the div is in the view and then start the animation to make the div visible.

However, this doesn't work fine when I have two divs in the same component i.e, as soon as the first div is in the view - animate and show the first div, and when you scroll further as soon as the second div is in the view - animate and show the second div.

Any help would be appreciated.

Here's the code:

import { motion } from 'framer-motion';
import { useInView } from 'react-intersection-observer';

function Container(props) {

    const { ref, inView } = useInView({
        threshold: 1
    });

    const { ref1, inView1 } = useInView({
        threshold: 1
    });

    return (
        <div>
            <motion.div ref={ref}>
                <motion.h1 
                   initial={{  x: -700, opacity: 0 }} 
                   animate={ inView ? { x: 0,  opacity: 1 } : ''} 
                   transition={{ duration: .75 }} >
                     Sample Title 1
                </motion.h1>
                <motion.p 
                   initial={{  x: 400, opacity: 0 }} 
                   animate={ inView ? { x: 0,  opacity: 1 } : ''} 
                   transition={{ delay: 0.8, duration: 1, ease: "easeOut" }} >
                     Sample Description 1
                </motion.p>
            </motion.div>

            <motion.div ref={ref1}>
                <motion.h1 
                   initial={{ opacity: 0 }} 
                   animate={ inView1 ? { opacity: 1 } : ''} 
                   transition={{ duration: .75 }} >
                     Sample Title 2
                </motion.h1>
                <motion.p
                   initial={{  x: 400, opacity: 0 }} 
                   animate={ inView1 ? { x: 0,  opacity: 1 } : ''} 
                   transition={{ delay: 0.8, duration: 1, ease: "easeOut" }} >
                     Sample Description 2
                </motion.p>
            </motion.div>         
        </div>
    );
}

export default Container;




Solution

  • I guess you should correctly connect animation with intersection events

    1. Animation control: https://www.framer.com/api/motion/utilities/#animate
    2. InVew from 'react-intersection-observer' with
    const from = useMotionValue(0);
    
    useEffect(
      () => {
        if (inView) {
          const controls = animate(x, 100, {
            type: "spring",
            stiffness: 2000,
          })
    
          return controls.stop
        }
      },
      [inView]
    }