Search code examples
next.jsreact-hooksscrollframer-motion

Different animation by screen-size on nextjs & framer-motion


I'm using nextjs & framer-motion for scroll animation. I want to have different options depending of the screensize, whether in offset or in opacity values. It should run the right values on load but also on resize.

My page structure is as such:

<main className='home-container'>
<SliceZone slices={page.data.slices} components={components} />
</main>

And each slide is composed as :

 <>
<PrismicLink href={`project/${projectslug}`}>
<motion.section ref={ref}
  className={`home-layout home-layout-1 ${sliceVariation}`}
  data-slice-type={slice.slice_type}
  data-slice-variation={slice.variation}
>
content Here
</motion.section>
</PrismicLink>
</>

I'm using

import { useScroll, useInView, motion, AnimatePresence, stagger, useAnimation, useTransform } from "framer-motion"
import { useEffect, useState, useRef } from 'react';
import { useMediaQuery } from "react-responsive";

Then :

const Home2Images = ({ slice }) => {


 const ref = useRef(null);

  ///// SCROLL OPACITY ANINMATION /////
  
  const isDesktop = useMediaQuery({ query: '(min-width: 768px)' });

  const handleMediaQueryChange = (matches) => {
    if (matches) {
      console.log("DESKTOP");
    } else {
      console.log("MOBILE");
    }
  };
  handleMediaQueryChange(isDesktop);


  useEffect(() => {
  handleMediaQueryChange(isDesktop);
  }, [isDesktop]); 


// then the code to check for scroll

  const {scrollYProgress} = useScroll({
      target:ref,
      offset: isDesktop ? ['start 80%', 'start 50%'] : ["start 55%", "end 10%"]
    })
    const opacity = useTransform(scrollYProgress, isDesktop ? [0, 1] : [0, 0.3, 0.7, 1], isDesktop ? [0.3, 1] : [0.25,1, 1, 0.25]);
  

How can I change that code so that on resize, it updates the values of opacity & offset?


Solution

  • I finally found an answer, I set the isDesktop initially, then it re-renders on useeffect with key={isDesktop}.

    const [isDesktop, setIsDesktop] = useState(false);
      const desktop = useMediaQuery({ query: "(min-width: 768px)" });
      useEffect(() => {
        setIsDesktop(desktop);
      }, [desktop]);
    
    
      handleMediaQueryChange(isDesktop);
    
      useEffect(() => {
        handleMediaQueryChange(isDesktop);
      }, [isDesktop]);
    
      ///SCROLLS PARAMETERS
      const ref = useRef(null);
      const { scrollYProgress } = useScroll({
        target: ref,
        offset: isDesktop ? ["start 80%", "start 50%"] : ["start 65%", "end 15%"],
      });
      const opacity = useTransform(
        scrollYProgress,
        isDesktop ? [0, 1] : [0, 0.4, 0.8, 1],
        isDesktop ? [0.3, 1] : [0.25, 1, 1, 0.25]
      );
    

    and use this on the div:

    <motion.div
        id={slice.id}
        ref={ref}
     key={isDesktop}
        style={{ opacity }}
      >