参考错误:window undefined - 开发人员指南
您是否曾经在控制台中看到过此错误并想知道发生了什么?您并不孤单!臭名昭著的“窗口未定义”错误是使用 React、Next.js 或任何服务器端渲染 (SSR) 应用程序的开发人员最常见的麻烦之一。
这个错误是怎么回事?🤔
首先,让我们了解“window”到底是什么。在基于浏览器的 JavaScript 中,“window”是一个代表浏览器窗口的全局对象。它包含各种有用的东西,例如:
问题是什么?这个对象只存在于浏览器中。当你的代码在服务器上运行时(比如在 SSR 期间),没有浏览器,因此也没有 `window` 对象!

发生此错误的常见情况
当您尝试直接在组件中访问窗口属性时(尤其是在初始渲染期间),您会遇到此错误。这通常在检查屏幕尺寸或浏览器功能时发生:
// This will break during SSR const screenWidth = window.innerWidth;
许多浏览器专用库都假设它们在客户端环境中运行。当这些库尝试在服务器端渲染期间访问窗口时,您的应用程序将崩溃:
// Some libraries assume window exists import someLibrary from 'browser-only-library';
localStorage 是客户端存储中经常访问的窗口属性。在服务器渲染期间尝试使用它将触发错误:
// This will fail on the server const savedData = localStorage.getItem('user-data');
如何修复?💪
1. 使用 useEffect Hook
最直接的解决方案是将特定于浏览器的代码包装在 `useEffect` 钩子中:
import { useEffect } from 'react'; function MyComponent() { useEffect(() => { // Safe to use window here const screenWidth = window.innerWidth; console.log('Screen width:', screenWidth); }, []); returnMy Component; }
2. 检查窗口是否已定义
创建一个实用函数来安全地检查窗口:
const isClient = typeof window !== 'undefined'; function MyComponent() { if (isClient) { // Safe to use window here } returnMy Component; }
3. 动态导入(Next.js 解决方案)
对于 Next.js 应用程序,使用带有 `ssr: false` 的动态导入:
import dynamic from 'next/dynamic'; const BrowserOnlyComponent = dynamic( () => import('../components/BrowserComponent'), { ssr: false } );
专业提示🌟
使用这些久经考验的模式避免“窗口未定义”错误:
function useWindowSize() { const [size, setSize] = useState({ width: 0, height: 0 }); useEffect(() => { const updateSize = () => { setSize({ width: window.innerWidth, height: window.innerHeight }); }; window.addEventListener('resize', updateSize); updateSize(); return () => window.removeEventListener('resize', updateSize); }, []); return size; }
function MyComponent() { const [isMounted, setIsMounted] = useState(false); useEffect(() => { setIsMounted(true); }, []); if (!isMounted) { return null; // or a loading state } returnBrowser-only content; }
需要注意的常见问题⚠️
测试你的代码
请记住在服务器和客户端环境中测试您的应用程序。以下是一个简单的测试设置:
describe('MyComponent', () => { it('handles server-side rendering', () => { // Test SSR scenario const { container } = render(); expect(container).toBeInTheDocument(); }); it('handles client-side rendering', () => { // Mock window object const { container } = render( ); expect(container).toBeInTheDocument(); }); });
结论
“窗口未定义”错误乍一看可能很吓人,但一旦您了解了它发生的原因,处理起来其实很简单。请记住:
如果您想了解有关窗口对象的更多信息,可以阅读 MDN Web Docs。

祝你编码愉快!🚀