Next.js: 问:如何只在客户端执行代码

创建于 2017-07-05  ·  19评论  ·  资料来源: vercel/next.js

我的应用程序中有一个回调路由,它从 URL 哈希片段中的身份验证进程接收访问令牌。 我想解析它并保存到 redux 存储中。 在切换到下一个之前,我曾经通过window.location.hash获取它,但是当页面呈现服务器端时这不可用(哈希片段显然没有发送到服务器,所以我无法在那里解析它)。

有没有办法限制某些代码只能在客户端执行? 或者有没有其他方法可以实现这一目标?

最有用的评论

@vanniewelt您可以随时查看process.browser ..

if (process.browser) {
  // client-side-only code
}

@Timer编辑:

@vanniewelt您可以随时查看typeof window ..

if (typeof window !== 'undefined') {
  // client-side-only code
}

所有19条评论

@vanniewelt :在客户端加载动态导入的异步组件,您可以将所有客户端逻辑放在那里。

此外 ComponentWillReceiveProps 生命周期将在服务器端接收道具中的请求。
可以检查此变量是否存在并注入您的客户端代码。

如果库需要窗口变量,我建议您使用动态导入,对我来说效果很好。

https://github.com/zeit/next.js/tree/v3-beta/examples/with-dynamic-import

你也可以使用 React 的componentDidMount生命周期方法。 它不称为服务器端。

@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

这似乎是这个问题的有效答案:

有没有办法限制某些代码只能在客户端执行?

@sarkistlt componentDidMount只在客户端执行, componentWillMount在客户端和服务器端都执行。

@sarkistlt https://reactjs.org/docs/react-component.html#componentwillmount

这是在服务器渲染上调用的唯一生命周期钩子。

我做了很多次,你把componentWillMountcomponentDidMount混淆

@sergiodxa实际上你是对的,刚刚运行了测试。 谢谢!

我需要mapbox-gl模块,它是ComponentDidMount一个客户端库,并摆脱了一个丑陋的错误ReferenceError: self is not defined

我无法使用componentDidMount制作 Mapbox,因为该组件仍会尝试在服务器上进行处理(我不知道究竟要做什么)(我最终遇到了与 @elaich 相同的问题) )。

使用@aga5tya建议的动态导入可以解决问题🎉。

@vanniewelt :在客户端加载动态导入的异步组件,您可以将所有客户端逻辑放在那里。

此外 ComponentWillReceiveProps 生命周期将在服务器端接收道具中的请求。
可以检查此变量是否存在并注入您的客户端代码。

如果库需要窗口变量,我建议您使用动态导入,对我来说效果很好。

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,我再次编辑以反映原始评论您的编辑。

  1. 为什么我们应该使用typeof window !== 'undefined'而不是process.browser ? 它更冗长,所以如果这里没有理由,我更喜欢使用process.browser
  2. 下次您编辑贡献者评论时,您能否在评论中显示编辑内容? 首先,它会使线程变得混乱,就像这里所做的那样,以下评论是对我的具体评论的回复。 其次,它具有误导性,因为那不是我写的,也不是人们在做出反应时阅读的内容。

为什么我们应该使用 typeof window !== 'undefined' 而不是 process.browser? 它比较冗长,所以如果这里没有理由,我更喜欢使用 process.browser。

process.browser是非标准的,仅在 webpack 环境中可用,这意味着它在未来可能会崩溃,例如 webpack 5 不再填充process

typeof window !== "undefined"的替代方案可能是Object.prototype.isPrototypeOf(window) 。 然而,根据这篇文章,Next.js 生成的包检测到先验,并且任何产生更轻的包都应该被视为胜利。

此页面是否有帮助?
0 / 5 - 0 等级

相关问题

rauchg picture rauchg  ·  3评论

knipferrc picture knipferrc  ·  3评论

havefive picture havefive  ·  3评论

pie6k picture pie6k  ·  3评论

DvirSh picture DvirSh  ·  3评论