Creating a Custom Hook for In View Animations in React

This tutorial teaches you how to create a custom React hook for handling in-view animations using framer-motion and react-intersection-observer.

Importing Dependencies

First, we need to import useAnimation from framer-motion, and useEffect, useState from react, and useInView from react-intersection-observer.

import { useAnimation } from 'framer-motion'; import { useEffect, useState } from 'react'; import { useInView } from 'react-intersection-observer';

Creating the useInViewAnimation Hook

Next, we define our custom hook useInViewAnimation. This hook takes an optional parameter initialState which defaults to false.

const useInViewAnimation = (initialState = false) => {...};

Adding State and Animation Controls

Inside our hook, we declare two state variables: isComponentVisible and setIsComponentVisible, and animation controls using useAnimation.

const controls = useAnimation(); const [isComponentVisible, setIsComponentVisible] = useState(initialState);

Setting up Intersection Observer

We then set up the intersection observer using useInView hook. We set triggerOnce to false and threshold to 0.1.

const [ref, inView] = useInView({   triggerOnce: false,   threshold: 0.1, });

Adding an Effect

We add an effect that starts the 'show' animation if the component is in view and 'hidden' animation if it's not. We also update the isComponentVisible state accordingly.

useEffect(() => {   if (inView) {     controls.start('show');     setIsComponentVisible(true);   } else {     controls.start('hidden');     setIsComponentVisible(false);   } }, [controls, inView]);

Returning the Result

Finally, our hook returns an object containing ref, controls, and isComponentVisible.

return { ref, controls, isComponentVisible };

Complete Code

Here is the complete code of the custom hook useInViewAnimation.

import { useAnimation } from 'framer-motion'; import { useEffect, useState } from 'react'; import { useInView } from 'react-intersection-observer'; const useInViewAnimation = (initialState = false) => {   const controls = useAnimation();   const [isComponentVisible, setIsComponentVisible] = useState(initialState);   const [ref, inView] = useInView({     triggerOnce: false,     threshold: 0.1,   });   useEffect(() => {     if (inView) {       controls.start('show');       setIsComponentVisible(true);     } else {       controls.start('hidden');       setIsComponentVisible(false);     }   }, [controls, inView]);   return { ref, controls, isComponentVisible }; }; export default useInViewAnimation;