提问人:H3lltronik 提问时间:3/10/2023 最后编辑:Chris HamiltonH3lltronik 更新时间:6/12/2023 访问量:8251
下一页.js 13 “未定义窗口”
Next.js 13 "window is not defined"
问:
我写了一个看起来像这样的组件:
'use client'
export const HorizontalModule = (props: any) => {
...
return (
{scrollPosition >= 0 && (
<FirstModule />
)}
{scrollPosition >= window.innerHeight * 2 && (
<SecondModule />
)}
)
})
但是我收到了“窗口未定义”错误。
通过阅读不同的帖子,我发现大多数人发现使用动态导入很有用,所以我在 nextjs 页面的父组件中执行了此操作:
const HorizontalModule = dynamic<any>(
() => import('./HorizontalModule/HorizontalModule').then((mod) => mod.HorizontalModule),
{
ssr: false,
suspense: true,
loading: () => <p>Loading...</p>
}
)
起初我收到此错误:“对象不是函数”
现在我收到“不支持的服务器组件类型:未定义”
我不完全知道我做了什么来切换错误,但它仍然不起作用。
我必须提一下,我在 HorizontalModule 代码中都使用了 window 对象,但当我在 render 函数中使用它时,一切都停止工作。useEffects
我还尝试在组件内部编写如下验证:
if (window === undefined) return (<></>)
return (...)
我收到了相同的窗口未定义对象或水化错误。
我不知道还有什么可做的,ssr false不起作用,悬念也一样,窗口条件......
答:
来自下一个.js 13 个文档:https://beta.nextjs.org/docs/rendering/server-and-client-components#client-components
[客户端组件] 在服务器上预呈现,并在客户端上冻结。
因此,该指令不会完全在客户端上呈现页面。它仍将在服务器上执行组件代码,就像在 Next.js 12 及更低版本中一样。在使用服务器上不可用的东西时,您需要考虑到这一点。'use client'
window
您不能只检查窗口是否已定义,然后立即在客户端上更新,因为这可能会导致服务器预渲染和客户端初始渲染之间不匹配(也称为冻结错误)。
要在客户端加载时更新页面,您需要将 useEffect
钩子与 useState
钩子结合使用。由于是在初始渲染期间执行的,因此状态更新在下一次渲染之前不会生效。因此,第一次渲染与预渲染匹配 - 没有水化错误。更多信息在这里: https://nextjs.org/docs/messages/react-hydration-erroruseEffect
与其在每个需要它的组件中创建此机制,不如创建一个上下文,该上下文只需使用 ,告诉我们可以安全地执行客户端代码。useEffect
是客户端-ctx.jsx
const IsClientCtx = createContext(false);
export const IsClientCtxProvider = ({ children }) => {
const [isClient, setIsClient] = useState(false);
useEffect(() => setIsClient(true), []);
return (
<IsClientCtx.Provider value={isClient}>{children}</IsClientCtx.Provider>
);
};
export function useIsClient() {
return useContext(IsClientCtx);
}
_app.jsx
function MyApp({ Component, pageProps }) {
return (
<IsClientCtxProvider>
<Component {...pageProps} />
</IsClientCtxProvider>
);
}
用法
const isClient = useIsClient();
return (
<>
{scrollPosition >= 0 && <FirstModule />}
{isClient && scrollPosition >= window.innerHeight * 2 && <SecondModule />}
</>
);
现场演示:https://stackblitz.com/edit/nextjs-mekkqj?file=pages/index.tsx
评论
ReferenceError: createContext is not defined
import { createContext } from 'react'
'use client'
import { useEffect, useState } from 'react'
type IUseStickyHeaderProps = {
active: boolean
}
export const useStickyHeader = ():IUseStickyHeaderProps => {
const [active, setActive] = useState(false)
useEffect(() => {
window.addEventListener('scroll', () => {
if (window.scrollY > 70) {
setActive(true)
} else {
setActive(false)
}
})
}, [])
return {
active
}
}
评论