SYSTEM: ONLINE
VER. ...
SLEET LOG
SLEET'S LOG
/2023年3月31日/1 MIN READ

在next.js中使用localstorage的踩坑

next.js auth

预期想在next.js中根据登录情况选择性在header中显示头像或登录按钮,但是往往并不能在组件中获取localstorage的值。若尝试这么做,将会报错:nextjs ReferenceError: localStorage is not defined

会发生这个问题,是因为next.js默认使用ssr。程序运行在服务器端,自然不存在window对象

为解决这一问题,我尝试使用如下方法解决:

  1. 通过context建立authprovider,使得登录情况可以在全局获取
  2. 通过hooks建立useauth,用usestate和usememo保存登录情况
  3. 通过swr以发送请求的方式请求localstorage的数据

显然,2方法会报错;1方法理论上可行,但实际操作时没有表现出很好的效果

最后使用了swr封装了一层请求localstorage的函数,代码如下:

tsx
import useSWR from 'swr'; // 需要判断代码是否运行在浏览器端 const isSSR = typeof window ==='undefined' const useStorage = (key: string, defaultValue?: any) => { if(isSSR) return; const {data} = useSWR(key, async(key)=>{ const value = localStorage.getItem(key)||defaultValue; return value; }); const getToken = () => { return data; }; const setToken = (newVal: string) => useSWR([key, newVal], async([key, newVal])=>{ localStorage.setItem(key, newVal) }) const delToken = () => useSWR(key, async(key)=>{ localStorage.removeItem(key) }); return { getToken, setToken, delToken } } export default useStorage;

在组件中使用方式如下:

tsx
// src/components/header import useStorage from "@/hooks/useStorage"; export default function Head() { const authStorage = useStorage(tokenName); if(!Boolean(authStorage?.getToken())){ Router.push('/login') return <></> } return ( <section> { Boolean(authStorage?.getToken()) ? <Avatar /> : <Link href="login">登录</Link> } </section> ) }

需要注意的是,如果涉及到请求相关的函数(如自行创建请求示例来拦截每次请求,并尝试将token添加到auth头时),则不应该使用上文提到的authstorage,直接localstorage获取即可。

ts
// src/service/request.ts instance.interceptors.request.use( (config: any) => { const token = localStorage.getToken(token_name); if (token) { config.headers.Authorization = token; } return config }, function (error) { return Promise.reject(error) } )
Article Index