Next.js 13:根据屏幕大小有条件地应用初始帧运动动画值时出现水合错误

ntjbwcob  于 2023-03-18  发布在  其他
关注(0)|答案(1)|浏览(104)

我在Next.js 13中编写了一个应用程序,我使用framer-motion来制作动画。它由一个页面组成,分为几个屏幕,导航通过滚动到它们的部分ID来进行。我使用旧的pages目录。
其中一个屏幕上的动画使元素在滚动视图时从侧面滑入。在大屏幕上有一个侧边栏,但在移动的上是隐藏的。因此,在大屏幕上,我必须为元素设置一个不同的初始X位置,向右偏移,否则它们会隐藏在侧边栏下面,框架的whenInView不会触发。
我用这些代码来解决这个问题:
1.一个实用程序函数,它 Package 浏览器的matchMedia函数,以提供css文件之外的屏幕信息:

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.元素初始X位置的不同值,例如:

<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.在所有具有动态初始值的屏幕上,我添加了:

'use client';

问题是我每次刷新都会得到水合错误。
一个三个三个一个
这个问题看起来很明显,但是我不确定如何解决它。我认为'use client'应该将这个组件排除在服务器渲染之外。或者它只在新的app目录中工作吗?另外,你认为在useEffect钩子中设置初始值可以解决这个问题吗?

owfi6suc

owfi6suc1#

所以,我自己设法解决了这个问题。显然,framer-motion在处理风格等 prop 时足够智能,可以区分客户端和服务器,但在应用的另一部分,我有一个基于isMobile()函数的完整条件渲染。它在服务器上解析为false,因为window未定义,但在客户端上,当在响应模式下使用Chrome dev-tools时,它将为true。
因此,这段代码将破坏整个过程,尽管错误是关于其他方面的:

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

我通过创建一个客户端专用的 Package 器组件来解决这个问题:

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

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

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

希望这对某人有帮助!

相关问题