我的应用程序中有一个回调路由,用于从 URL 哈希片段中的身份验证进程接收访问令牌。我想解析它并保存到 redux 存储中。我曾经在切换到下一个之前完成它window.location.hash
,但是当页面呈现服务器端时,这是不可用的(而且哈希片段显然没有发送到服务器,所以我无法在那里解析它)。
有没有办法限制某些代码仅在客户端执行?或者还有其他方法可以实现这一目标吗?
我的应用程序中有一个回调路由,用于从 URL 哈希片段中的身份验证进程接收访问令牌。我想解析它并保存到 redux 存储中。我曾经在切换到下一个之前完成它window.location.hash
,但是当页面呈现服务器端时,这是不可用的(而且哈希片段显然没有发送到服务器,所以我无法在那里解析它)。
有没有办法限制某些代码仅在客户端执行?或者还有其他方法可以实现这一目标吗?
@vanniewelt:动态导入的异步组件加载在客户端上,您可以将所有客户端逻辑放在那里。
此外,ComponentWillReceiveProps 生命周期将在服务器端接收 props 中的请求。可以检查该变量是否存在并注入您的客户端代码。
如果库需要窗口变量,我建议您使用动态导入,对我来说效果很好。
https://github.com/zeit/next.js/tree/v3-beta/examples/with-dynamic-import
您还可以使用componentDidMount
React的生命周期方法。它不称为服务器端。
@vanniewelt 你可以随时看看process.browser
..
if (process.browser) {
// client-side-only code
}
由@Timer编辑:
@vanniewelt 你可以随时看看typeof window
..
if (typeof window !== 'undefined') {
// client-side-only code
}
是的,但这不是最好的方法。假设我想检查用户是否经过身份验证,并且出于多种原因我只想在客户端运行该检查,其中之一是因为我将 JWT 存储在 localStorage 中并且不想将其存储在 cookie 中。所以在这种情况下,在第一页加载:
if (process.browser) {
// client-side-only code
}
范围内的代码根本不会被执行,不会在服务器上也不会在客户端上执行,只有当客户端触发路由更改时才会执行
@sarkistlt 在某些情况下你可能是对的,具体取决于代码的放置位置..但是..
如果该代码在服务器上执行,则执行将不会到达// client-side-only code
。如果该代码在客户端执行,执行将达到// client-side-only code
。
这似乎是这个问题的有效答案:
有没有办法限制某些代码仅在客户端执行?
@sarkistltcomponentDidMount
仅在客户端执行,componentWillMount
在客户端和服务器端均执行。
@sarkistlt https://reactjs.org/docs/react-component.html#componentwillmount
这是在服务器渲染上调用的唯一生命周期挂钩。
我做了很多次,你混淆componentWillMount
了componentDidMount
。
@sergiodxa 实际上你是对的,刚刚运行了测试。谢谢!
@sergiodxacomponentWillMount
的链接更改为 https://reactjs.org/docs/react-component.html#unsafe_componentwillmount。
我需要mapbox-gl
一个模块,它是内部的客户端库ComponentDidMount
,并摆脱了一个丑陋的错误ReferenceError: self is not defined
我无法使用 Mapbox,componentDidMount
因为该组件仍然尝试在服务器上进行处理(我不知道到底要做什么)(我最终遇到了与@elaich 相同的问题)。
按照 @aga5tya 的建议使用动态导入可以解决问题吗?
@vanniewelt:动态导入的异步组件加载在客户端上,您可以将所有客户端逻辑放在那里。
此外,ComponentWillReceiveProps 生命周期将在服务器端接收 props 中的请求。可以检查该变量是否存在并注入您的客户端代码。
如果库需要窗口变量,我建议您使用动态导入,对我来说效果很好。
https://github.com/zeit/next.js/tree/v3-beta/examples/with-dynamic-import
对于那些遇到此线程寻找解决方案的人。上面列出的动态导入链接已损坏。它已更新,可以在Dynamic Imports中找到。
如果您有一个始终应该在客户端上执行的组件,并且不想使用动态导入(例如:人们可能会忘记他们需要使用它们),您可以使用 Hooks (或等效的componentDidMount
),如下所示:
import React, { useEffect, useState } from 'react'
function CreateInteraction ({ input }) {
const [isComponentMounted, setIsComponentMounted] = useState(false)
useEffect(() => setIsComponentMounted(true), [])
if(!isComponentMounted) {
return null
}
return <h1>I'm only executed on the client!</h1>
}
只是为了添加一些已经很好的答案:我当前的项目在两个方向上做了很多条件渲染,所以我为此使用了一个组件:
import React, { useEffect, useState } from "react";
export interface ConditionallyRenderProps {
client?: boolean;
server?: boolean;
}
const ConditionallyRender: React.FC<ConditionallyRenderProps> = (props) => {
const [isMounted, setIsMounted] = useState(false);
useEffect(() => setIsMounted(true), []);
if(!isMounted && props.client) {
return null;
}
if(isMounted && props.server) {
return null;
}
return props.children as React.ReactElement;
};
export default ConditionallyRender;
然后使用它如下:
<Layout>
<ConditionallyRender server>
<p>This is rendered only on server.</p>
</ConditionallyRender>
<ConditionallyRender client>
<p>This is rendered only on client.</p>
</ConditionallyRender>
</Layout>
如果您使用任何访问浏览器 API 的库,那么您可以使用 SSR=false 作为第二个参数动态导入模块。
const DynamicComponentWithNoSSR = dynamic( () => import('../components/hello3'), { ssr: false } )
https://nextjs.org/docs/advanced-features/dynamic-import
如果您使用任何访问浏览器 API 的库,那么您可以使用 SSR=false 作为第二个参数动态导入模块。
const DynamicComponentWithNoSSR = dynamic( () => import('../components/hello3'), { ssr: false } )
https://nextjs.org/docs/advanced-features/dynamic-import
如果您想对查看 @yashwant-dangi 代码的任何人使用“动态”导入,您还需要添加此导入!
import dynamic from 'next/dynamic'
@Timer我注意到您编辑了我的评论https://github.com/vercel/next.js/issues/2473#issuecomment-362119102,我再次编辑了该评论以反映原始评论和您的编辑。
typeof window !== 'undefined'
而不是仅仅process.browser
?它比较冗长,所以如果没有原因,我更喜欢使用process.browser
.为什么我们应该使用 typeof window !== 'undefined' 而不仅仅是 process.browser ?它比较冗长,所以如果没有原因的话,我更喜欢使用 process.browser。
process.browser
是非标准的,仅在 webpack 环境中可用,这意味着它将来可能会被破坏,例如 webpack 5 不再使用 polyfills process
。
在 Next 中预见一个不需要开发人员编写样板文件的 api 是很有用的。仅在客户端环境中应用一些 JS 是很常见的,并且必须创建自定义组件是样板文件,可以将其提取为易于使用的简单方法调用。
由于最近没有活动,此问题已被自动锁定。如果您遇到类似问题,请创建一个新问题并包含重现步骤。谢谢。