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

Posted

技术标签:

【中文标题】React JS 服务器端问题 - 找不到窗口【英文标题】:React JS Server side issue - window not found 【发布时间】:2016-12-21 11:03:05 【问题描述】:

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

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

我猜这个问题可能出在同构工具上,但我不知道如何将导入包推迟到已经定义窗口的客户端。

【问题讨论】:

【参考方案1】:

在进行服务器端渲染时,windowdocument 等全局变量将未定义。而如果你想用同构的方式来做,你必须测试渲染组件时是什么环境。

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

github上有很多示例代码,上面的链接就是其中之一,希望对你有帮助。

【讨论】:

【参考方案2】:

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

注意:最初,当您启动项目时,它会渲染出一个完整的 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字符串,然后让客户端获取结束了。

另外注意:不用担心将window设置为空对象,一旦客户端完成渲染,它就会恢复正常。

【讨论】:

我应该在哪里添加“mySpecialWindowFunction”? 除了 Spacemoose 的评论之外,可以更新答案以指定第一个 sn-p 进入 webpack 配置中的 module.exports = plugins[ ] 区域。 有人可以回答@Spacemoose 的问题吗? 请添加使用“mySpecialWindowFunction”的详细信息【参考方案3】:

这是一个可以为你处理窗口、文档和全局对象的 npm 库:Global。

那么你就可以放心地写了:

import window from 'global'

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

【讨论】:

我必须在哪里添加这个?【参考方案4】:

我尝试在我的常量中将其设置为全局导入:

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】:

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

【讨论】:

【参考方案6】:

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

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

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

如果没有设置该选项,它将退回到 window,它正在处理仅限客户端的代码。

【讨论】:

【参考方案7】:

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

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

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

您的 window && if (window) 检查失败,因为在 javascript 中未声明和“未定义”是不同的东西。

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

对原始问题的回答是,无论何时访问需要的“窗口”对象,您都需要使它们成为有条件的:

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

【讨论】:

以上是关于React JS 服务器端问题 - 找不到窗口的主要内容,如果未能解决你的问题,请参考以下文章

窗口未使用服务器端渲染 React 和 Express 定义

React 前端,Node JS 后端托管

使用 PHP 进行 React.js 服务器端渲染

在连接窗口ssms中找不到Integrations服务

错误:在 next.js 中找不到模块“swiper/react”

asp.net - 使用 js 执行 AsyncPostBack