In my Next.js 13 app, I am utilizing framer-motion for animations on a single-page layout with multiple screens. Navigation is achieved by scrolling to their respective section IDs, and I am using the traditional pages
directory.
One of the screens features elements sliding in from the side when scrolled into view. On larger screens, there is a sidebar that is hidden on mobile devices. To prevent the elements from being hidden underneath the sidebar and causing issues with framer-motion's whenInView
trigger, I have adjusted the initial X position of the elements accordingly.
To address this, I have implemented the following code snippets:
- A utility function that utilizes the browser's
matchMedia
function to determine if the device is mobile:
export const isMobile = (): boolean => {
if (typeof window === 'undefined') return false;
const query = '(min-width: 320px) and (max-width: 767.98px)';
const match = window.matchMedia(query);
return match.matches;
}
- Different values for the initial X position of the elements based on the device type:
<motion.h1
initial={{ x: isMobile() ? '93vw' : '86vw' }}
whileInView={{ x: 0 }}
transition={{ duration: 0.75, type: 'spring' }}
viewport={{ once: true }}
className={classes.element}
>
Example content
</motion.h1>
- I included the following above all screens with dynamic initial values:
'use client';
However, each time I refresh the page, I encounter a hydration error:
Warning: Prop `style` did not match. Server: "transform:translateX(86vw) translateZ(0)" Client: "transform:translateX(93vw) translateZ(0)"
Uncaught Error: Hydration failed because the initial UI does not match what was rendered on the server.
The issue appears straightforward, but I am unsure of how to resolve it. I believed that 'use client'
would exclude this component from server rendering. Does it only work in the new app
directory? Additionally, do you think setting the initial value within a useEffect
hook could potentially solve the problem?