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;