Search code examples
reactjsmedia-queriesreact-spring

Media query based React Spring animations/transitions


I've got this React Spring transition working nicely:

const Nav = () => {

  const[showMenu, setShowMenu] = useState(false)

  const navbgTransitions = useTransition(showMenu, null, {

      //FROM
      from: { 
        opacity: 1, position:'absolute', transform: 'translateX(225px)', 
      },

      //ENTER
      enter: { 
        opacity: 1, transform: 'translateX(0)'
      },

      //LEAVE
      leave: item => async (next, cancel) => {
        await new Promise(resolve => setTimeout(resolve, 500));
        await next({ opacity: 1, transform: 'translateX(225px)' })
      },
      
  })

})


return (
      <>
          {
            navbgTransitions.map(({ item, key, props }) =>
              item && 
              <animated.div key={key} style={props} className="background">
                <ul>
                    <Link onClick={() => setShowMenu(false)} to="/" exact><li>Home</li></Link>
                    <Link onClick={() => setShowMenu(false)} to="/about"><li>About</li></Link>
                    <Link onClick={() => setShowMenu(false)} to="/work"><li>Work</li></Link>
                    <Link onClick={() => setShowMenu(false)} to="/hire"><li>Hire Me</li></Link>
                </ul>
              </animated.div>
            )
          }

      </>
  );

export default Nav;

I've decided that I'd really like the animation to work differently on smaller devices. I was wondering, is there a way I can duplicate const navbgTransitions then wrap seperate React media queries around them and set the from, enter, and leave animations to play out differently depending on the viewport width?

I've done as much research as I can based on my understanding of React/Javascript and at the moment I'm tempted to switch over to react-transition-group as (from what I've read) this allows for stylesheet based animations.

I'm new to React so a bit of guidance would be greatly appreciated!


Solution

  • Yes, useMediaQuery from Material-ui can be used to determine the viewport width accordingly,

    const matches = useMediaQuery('(min-width:600px)');
    

    matches can then be used in your defined states for the transition to, for instance, use translateY on mobile devices instead of translateX (or whatever you want it to do for you),

    from: { 
            opacity: 1, 
            position:'absolute', 
            transform: matches ? 'translateX(225px)' : 'translateY(50px)', 
          },