Encountering a hydration issue in Next.js 13 due to applying initial framer-motion animation value conditionally depending on the screen size

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:

  1. 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;
}
  1. 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>
  1. 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?

Answer №1

After encountering an issue, I was able to find a solution on my own. It seems that framer-motion has the capability to differentiate between client and server when dealing with props like style. However, in another part of my application, I had implemented conditional rendering based on the isMobile() function. This caused a problem because it would return false on the server due to the undefined `window`, but true on the client side when utilizing Chrome dev-tools in responsive mode.

As a result, this snippet of code ended up breaking everything, even though the error appeared to be unrelated:

const renderLeftSide = (position: GridPosition): JSX.Element | null => {
    if (isMobile()) return null;
    return position === GridPosition.Left ? (
      <TimelineCard position={position} />
    ) : (
      <TimelineDate position={position} />
    );
  };

To resolve this issue, I came up with a solution by creating a component specifically for the client side:

const ClientOnly = ({ children }: PropsWithChildren) => {
  const [clientReady, setClientReady] = useState<boolean>(false);

  useEffect(() => {
    setClientReady(true);
  }, []);

  return clientReady ? <>{children}</> : null;
};

I hope this explanation proves useful to someone facing a similar challenge!

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Assistance needed with generating unique IDs in MongoDB

Currently, we rely on MongoDB's built-in ids for all of our unique id generation. However, there are specific cases where we must generate an id for an object before adding it to the database. One potential solution is to create an entry, retrieve th ...

Is there a way to implement a scrollbar that only scrolls through one specific column in an HTML table?

I need help adding a scrollbar to a specific column in an HTML table. Take a look at this scenario https://jsfiddle.net/6wpdc4tL/: https://i.stack.imgur.com/svzIg.png This table should have two scrollbars, one for the light blue SCROLL column and another ...

Can you please explain the distinction between UseGetSomeQuery argument values?

Just diving into RTK Query for redux and have a question about auto generated hooks. Can someone explain the difference in functionality between the two ways below? The first method seems correct based on the docs, but it's returning a 304 network s ...

Picture in the form of a radio button

Is there a way to use an image instead of a radio button in my AngularJS form? I have managed to hide the radio button using CSS, but it disables the checked event. How can I make the image clickable? position: absolute; left: -9999px; Here is the code s ...

Issue with angular directive scope not binding correctly

Good day I'm relatively new to Angular and directives, but I'm facing an issue with the scope (in my specific case). I have defined the directive as follows: angular.module('ToolBarMod', ['ngAria']) .controller('ToolBar ...

Having trouble embedding Hangouts button in HTML template using script tags

When I include a Hangouts button on my index page, it is visible and functional as expected: <body ng-app="sampleApp" ng-controller="MainCtrl"> <div class="row"> <div class="col-md-12 m-body"> <div class="m ...

The useSWR hook is failing to retrieve data from the API, even though performing a fetch() to the exact same

I am facing a challenge understanding why the useSWR function is not working in my application. Despite trying for two days, I am unable to pinpoint the reason. Surprisingly, the normal fetch function works seamlessly when calling the same API endpoint wit ...

JEST does not include support for document.addEventListener

I have incorporated JEST into my testing process for my script. However, I have noticed that the coverage status does not include instance.init(). const instance = new RecommendCards(); document.addEventListener('DOMContentLoaded', () => ...

Enhancing the functionality of XMLHttpRequest.open()

How can I intercept and modify the arguments of the XMLHttpRequest.open() method? I attempted using the proxy method, but it was unsuccessful. I removed the override when XMLHttpRequest() was called: (function() { var intercepted = window.XMLHttpReque ...

What steps should I take to ensure my sanity studio updates are reflected in my nextjs app?

Upon configuring my sanity studio with the initial data, everything seemed to be working well. However, when I try to make changes and publish them, the next app still displays the previous data. Even after deleting some information in the studio, the upda ...

Is barrel(index) file usage supported by Next.js 11.0.0?

When using barrel/index files with next.js, it appears to cause issues. It is unclear whether this is solely a webpack problem or if both webpack and next.js are affected. As stated in this report, tree shaking stops functioning properly when barrel files ...

Is it necessary to reload the page each time to see updates on the navbar in nextjs?

I recently developed a Next.js application with a Navbar component integrated into my layout.tsx file. The challenge arises when a user logs in and is redirected to the home page, which showcases a link in the Navbar for viewing their profile. However, I n ...

What is the process for adding information to datatables using jQuery?

I have been struggling to make a data table in jQuery function correctly. I am able to append data to the table, but the sorting, pagination, and search features are not working. Even though the data is visible in the table, it shows as 0 records. I am wor ...

Is it possible to exclude specific URLs from CSRF protection in sails.js?

I am currently integrating Stripe with my sails.js server and need to disable CSRF for specific URLs in order to utilize Stripe's webhooks effectively. Is there a way to exempt certain URLs from CSRF POST requirements within sails.js? I have searched ...

Testing a Svelte Component with Unit Tests { #conditionals }

Test Procedure Instructions To begin, execute the following bash command: mkdir example && cd example && mkdir src && touch jest.config.js && pnpm init && pnpm i @jest/globals @testing-library/svelte jest jest-envi ...

Having trouble receiving a JSON array after making an Ajax request

I have read through previous posts on this issue, but I still can't seem to figure it out. Hopefully, someone here can help me solve this problem. My challenge lies in retrieving an array, which I have encoded in json, from a PHP script and passing i ...

In the MUI v5 framework, when using nested modals, both the parent and child modal instances will close simultaneously

Here is the reproduction of my issue on codesandbox: https://codesandbox.io/s/trusting-babbage-ovj2we?file=/src/App.js A nested modal has been created where the parent modal opens a button leading to the child modal. The useState of the parent modal has b ...

How can I trigger a revalidation of a server component or page in NextJs v13.2 by utilizing an onClick event handler within the app directory?

Instead of automatically revalidating every 5 seconds with revalidate: 5, I would like to trigger the revalidation using an onClick event handler on the frontend ui react component. ...

Encountering difficulties with properly storing an array in MongoDB using Node.js and Mongoose

Can you point me in the right direction on how to properly store an array of data in mongodb using node/mongoose? I'm currently facing an issue where all my data is being saved as the first value in the array. Here's a snippet of my code: const ...

Display the chosen option in the console by using onChange() function; this is analogous to how onSelect()

I'm having trouble getting the value of a select element to log in the console. I managed to do this with an onSelect() method, but the onChange() method isn't returning anything. Here's what I tried with the onChange() method: <Form.Gr ...