next.js 如何修复验证组件时的水合错误

kokeuurv  于 2023-04-11  发布在  其他
关注(0)|答案(1)|浏览(147)

我有一个身份验证组件,可以检查用户是否有来自localstorage的token,下面是我的代码:

import { useRouter } from "next/router";
import { useState } from "react";
const Index = (WrappedComponent: any) => {

return (props: any) => {

if (typeof window !== "undefined") {
const Router = useRouter();

      const accessToken = localStorage.getItem("token");
    
    
      if (!accessToken) {
        Router.replace("/authentication/login");
        return null;
      }
    

    
      return <WrappedComponent {...props} />;
    }
    
    // If we are on server, return null
    return null;

};
};

export default Index;

我在/pages目录中使用它来创建我的组件,如下所示:

import PageContainer from "../src/components/container/PageContainer";
import FullLayout from "../src/layouts/full/FullLayout";
import ShortList from "@/src/components/dashboard/ShortList";
import withAuth from "@/src/auth";

const Index = () => {
  return (
    <FullLayout>
      <PageContainer title="Sample Page" description="this is Sample page">
        <ShortList />
      </PageContainer>
    </FullLayout>
  );
};

export default withAuth(Index);

但我得到了这个错误:错误:由于初始UI与在服务器上呈现的UI不匹配,水合失败。
我该怎么解决这个问题?
我的Next.js版本是13。
我尝试使用useState,但不起作用

kb5ga3dv

kb5ga3dv1#

在服务器上,typeof window将是undefined,但在客户端上,即使在初始渲染之前,window也不会再被定义,这会导致一个水化错误,因为你的服务器渲染的HTML与React在水化过程中呈现的HTML不同。
因为useEffect只在服务器上运行,你可以通过以下方式检查你是在客户端还是服务器上:

import { useRouter } from "next/router";
import { useState, useEffect } from "react";

const Index = (WrappedComponent: any) => {
  return (props: any) => {
    const [isMounted, setIsMounted] = useState(false);

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

    const Router = useRouter();

    if (!isMounted) {
      // If we are on the server, return null
      return null;
    }

    const accessToken = localStorage.getItem("token");

    if (!accessToken) {
      Router.replace("/authentication/login");
      return null;
    }

    return <WrappedComponent {...props} />;
  };
  
};

export default Index;

一般来说,这种检查:if (typeof window !== "undefined")总是导致错误,不能按预期工作。
我推荐这篇来自约书亚Comeau的关于React水合/再水合问题的文章https://www.joshwcomeau.com/react/the-perils-of-rehydration/#dynamic-sections-4
请记住,在这个例子中,索引页面最初将完全空白,因为它本质上是客户端呈现的,这可能会损害SEO。
要解决这个问题,您应该将auth数据存储在cookie中,并在next.js middleware中检查用户是否登录,并可能在中间件内部而不是客户端重定向。

相关问题