修复Next.js中window is not defined方法详解
Jovie 人气:0引言
这个问题与Next.js的服务器端渲染有关。Next.js默认会尝试为您的网站使用SSR。这意味着,由于我们是在服务器上而不是在浏览器中,所以 "窗口 "对象并不存在。解决这个问题的方法是强迫Next.js在浏览器中运行你的代码,我将解释如何做到这一点。
使用useEffect钩子
该useEffect钩子总是在浏览器中运行,所以我们可以用它来确保我们的代码只能从那里运行。关于钩子的快速入门知识,请查看这篇文章。
下面是一个简单应用的示例代码,它将用户最后一次访问网站的时间存储在本地存储中。如果你不熟悉在React或Next.js中使用localStorage,可以看看我们这里的这个教程,它使用了类似的方法。这个方法是相同的,但有一个小的区别,那就是你可以在vanilla React组件的主体中使用localStorage,因为默认没有SSR:
function updateLastSeen() { const lastSeen = window.localStorage.getItem('last-seen') ?? new Date(); window.localStorage.setItem('last-seen', new Date().toString()); return lastSeen; } function WindowPage() { const lastSeen = updateLastSeen(); return <div>Last Seen: {lastSeen}</div>; }
运行这个,我们得到这个你可能熟悉的错误:
为了解决这个问题,让我们引入一个自定义的钩子,它涉及一个 useEffect。
function useLastSeen() { const [lastSeen, setLastSeen] = useState(null); const retrieved = useRef(false); //To get around strict mode running the hook twice useEffect(() => { if (retrieved.current) return; retrieved.current = true; setLastSeen(updateLastSeen()); }, []); return lastSeen; }
我已经把我们的逻辑移到了一个自定义的钩子上,只是为了保持代码的简洁。现在随着我们代码的改变,代码将只在钩子运行时运行,也就是在客户端。
然后我们可以将我们的组件更新为。
function WindowPage() { const lastSeen = useLastSeen(); return ( <div> Last Seen: {lastSeen} </div> ); }
这段代码更简洁,而且由于 useEffect里面的钩子只在客户端运行,我们的错误就消失了
检查窗口是否被定义
另一种方法是在我们运行代码之前简单地检查窗口对象是否被定义。如果代码在服务器上运行,由于我们不在浏览器中,窗口对象就不存在。
我们不能使用与之前相同的例子,因为这种方法有一个关键的区别。因为我们没有等待组件的渲染,任何对页面HTML的差异都会导致服务器端渲染的页面版本与客户端不同,我们会在Next.js中得到一个错误。
在这个例子中,我们将为窗口对象添加一个事件监听器,以跟踪页面上的点击和它们的位置。
const isBrowser = () => typeof window !== 'undefined'; //The approach recommended by Next.js function WindowPage() { const [lastClick, setLastClick] = useState(''); if (isBrowser()) { //Only add the event listener client-side window.addEventListener('click', (e) => setLastClick(`${e.pageX}, ${e.pageY}`) ); } return ( <div className="m-auto rounded bg-violet-600 p-10 font-bold text-white shadow"> Click at: {lastClick} </div> ); }
正如我们所看到的,代码并没有在服务器上运行,所以Next.js现在很高兴了
希望这两种方法中的一种能帮助解决你的问题。我推荐第一种方法,因为它涵盖了大多数情况,而且你不必处理Next.js发现渲染不匹配的可能性。
加载全部内容