反应JS服务器端问题 - 找不到窗口

时间:2016-08-15 08:27:47

标签: javascript reactjs webpack serverside-rendering draftjs

您好我在reactJS项目中尝试使用react-rte。我有服务器端渲染,每次我想使用这个包时,我得到:

return /msie [6-9]\b/.test(window.navigator.userAgent.toLowerCase());
                               ^
ReferenceError: window is not defined

我想问题可能在于同构工具,但我不知道如何将包导入到已经定义窗口的客户端。

7 个答案:

答案 0 :(得分:9)

如果您正在进行服务器端渲染,那么全局窗口对象很可能未定义,因为这只是客户端会理解的内容。

  

注意:最初,当你启动你的项目时,它会渲染出一个完整的DOM字符串(此时它不会知道window,因为它是服务器端,然后使用您的窗口对象可用的客户端代码重新渲染!

我在这种情况下使用了一种解决方法。这就是我的webpack插件所拥有的:

new webpack.DefinePlugin({
  'process.env.NODE_ENV': isDevelopment ? '"development"' : '"production"',
  'process.env.BROWSER': JSON.stringify(true),
  __DEV__: isDevelopment
}),

所以我使用process.env.BROWSER对我有利,因为如果它是服务器端,它将被定义为undefined,如果客户端完成渲染,它将被true

由于当服务器端没有窗口对象时,一切都停止工作,我们可以添加:

const mySpecialWindowFunction = () => {

  /* START HACK */
  if (!process.env.BROWSER) {
    global.window = {}; // Temporarily define window for server-side
  }
  /* END HACK */

  return /msie [6-9]\b/.test(window.navigator.userAgent.toLowerCase());
};

这样,你的控制台就不会对你尖叫,也不会停止服务器端的渲染,现在你可以继续光荣的一天!虽然我不得不承认这有点 Hacky ,但它完成了工作,因为我们要做的就是让服务器端渲染出初始的DOM字符串然后让客户端接受结束了。

  

另请注意:不要担心将窗口设置为空对象,一旦客户端完成渲染,它将恢复正常。

答案 1 :(得分:8)

这是一个npm库,可以为您处理窗口,文档和全局对象:Global

然后你可以安全地写:

import window from 'global'

const mySpecialWindowFunction = () => {
    return /msie [6-9]\b/.test(window.navigator.userAgent.toLowerCase());
};

答案 2 :(得分:7)

对于试图弄清楚为什么SSR失败的其他人,即使他们正在检查窗口对象是否未定义。

您需要检查窗口引用是否存在,而不是它的值为空!

  if (typeof window === 'undefined') console.log('Window is not there')

您进行的window && if (window)检查失败,因为在JavaScript中未声明和'undefined'是不同的事情。

const a = undefined;
if (a) console.log('a');  // logs nothing, since 'a' is undefined
if (b) console.log('b');  // ReferenceError: b is not defined

原始问题的答案是,每当访问需要“ window”对象的对象时,您都需要使其成为条件对象:

return (typeof window === 'undefined') ?
   'node' :
   /msie [6-9]\b/.test(window.navigator.userAgent.toLowerCase());

答案 3 :(得分:0)

进行服务器端渲染时,windowdocument这样的全局变量将是未定义的。如果你想以同构方式进行,你必须测试渲染组件时的环境。

https://github.com/DavidWells/isomorphic-react-example

许多示例代码可以在github上找到,上面的链接就是其中之一,希望它有用。

答案 4 :(得分:0)

我尝试将其设置为全局导入:

export const GLOBAL_WINDOW = (typeof self === 'object' && self.self === self && self) || (typeof global === 'object' && global.global === global && global) || this;

在这种情况下,它会根据您在客户端应用程序或服务器上运行它的天气返回窗口或全局对象。

现在,您需要在要使用窗口对象的任何位置导入此常量。

例如:

import { GLOBAL_WINDOW } from '../constants/Constants';

const user = JSON.parse(GLOBAL_WINDOW.localStorage.getItem('user'));

答案 5 :(得分:0)

我发现的另一种解决方案是,可以在“ componentDidMount”事件中为状态变量分配“窗口变量”,然后在“渲染”方法中测试所需的状态变量是否为null或未定义,然后返回null,直到'componentDidMount'完成为止。

答案 6 :(得分:0)

我一直在使用针对客户端和服务器的ReactJS.NET目标构建,并遇到了同样的问题。

解决方案是将output.globalObject设置为'this'

module.exports = {
  // ...
  output: {
    // ...
    globalObject: 'this'
  }
};

在没有设置该选项的情况下,它会退回到window上,后者正在处理仅用于客户端的代码。