预期想在next.js中根据登录情况选择性在header中显示头像或登录按钮,但是往往并不能在组件中获取localstorage的值。若尝试这么做,将会报错:nextjs ReferenceError: localStorage is not defined
会发生这个问题,是因为next.js默认使用ssr。程序运行在服务器端,自然不存在window对象
为解决这一问题,我尝试使用如下方法解决:
- 通过context建立authprovider,使得登录情况可以在全局获取
- 通过hooks建立useauth,用usestate和usememo保存登录情况
- 通过swr以发送请求的方式请求localstorage的数据
显然,2方法会报错;1方法理论上可行,但实际操作时没有表现出很好的效果
最后使用了swr封装了一层请求localstorage的函数,代码如下:
tsximport 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