React JS 服务器端问题 - window 未找到

React JS Server side issue - window not found

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

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

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

做服务器端渲染时,全局如windowdocument将是未定义的。而如果你想以同构的方式来做,你必须测试渲染组件时的环境。

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

在github上可以找到很多示例代码,上面的link就是其中之一,希望对您有所帮助。

如果您正在执行服务器端呈现,则全局 window 对象很有可能未定义,因为那只是客户端会理解的内容。

Note: Initially, when you start up your project its going to render out a complete string of your DOM (at this point it will not know about window because it is server side, but then re-render with the client-side code to which your window object will be available!

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

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

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

因为当服务器端没有 window 对象时一切都会停止工作,我们可以添加:

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 字符串和然后让客户端接管。

Also Note: Don't worry about setting window as an empty object, it will be back to normal once the client-side finishes rendering.

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

那你就可以放心的写了:

import window from 'global'

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

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

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

在这种情况下,它 returns window 或全局对象取决于天气 运行 它在客户端应用程序或服务器上。

现在你需要在任何你想使用 window 对象的地方导入这个常量。

例如:

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

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

我发现的另一个解决方案是,您可以在 'componentDidMount' 事件中使用 'window variables' 分配状态变量,并且在 'render' 方法中您可以测试状态变量是否你想要的是 null 或 undefined 然后 return null,直到 'componentDidMount' 完成。

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

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

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

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

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

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

  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());

React 通过 'Suspense' 支持延迟加载,专门用于此类目的:

//add this to the top of your component
const RichTextEditor = React.lazy(() =>
  import("react-rte").then((module) => ({ default: module.Editor }))
);
render(){
     <Suspense fallback={<p>loading</p>}>
        <RichTextEditor />
     </Suspense>
}