服务器渲染-React Router Dom V^5.2.0 Error: Invariant failed: Browser history needs a DOM

Posted

技术标签:

【中文标题】服务器渲染-React Router Dom V^5.2.0 Error: Invariant failed: Browser history needs a DOM【英文标题】:Server Rendering-React Router Dom V^5.2.0 Error: Invariant failed: Browser history needs a DOM 【发布时间】:2020-09-08 16:49:56 【问题描述】:

我是 React 的初学者并且遇到了一些问题。我正在使用服务器渲染并使用 express 作为服务器并收到错误消息:错误:不变量失败:浏览器历史记录需要 DOM。我已经检查了来自各个站点的解决方案并应用了他们的解决方案,但是在应用不同的解决方案时遇到了不同的错误。如前所述,我收到一个错误:TypeError: Cannot read property 'location' of undefined 为此我通过从'react-router-dom 导入 -import BrowserRouter as Router 将路由器更改为 BrowserRouter ,然后我得到以下内容错误。

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import Route from 'react-router-dom';

import App from './components/App';

ReactDOM.hydrate(
 <Router><App /></Router> ,
  document.getElementById('mountNode'),
);

App.js

import React,  useState  from 'react';
import Route,Switch,browserHistory from "react-router-dom";
import  BrowserRouter as Router  from 'react-router-dom';
import  createMemoryHistory  from 'history';


import HomePage from './HomePage';
import About from './About';
export default function App()


//const history = createMemoryHistory();
    return (
    <Router history=browserHistory> 
        <Switch>
            <Route path="/" exact component=HomePage/>
            <Route path="/about" component=About/>  
        </Switch>
    </Router>
    );

错误

Error: Invariant failed: Browser history needs a DOM
at invariant (C:\LMS-APP\node_modules\tiny-invariant\dist\tiny-invariant.cjs.js:13:11)
at Object.createHistory [as createBrowserHistory] (C:\LMS-APP\node_modules\history\cjs\history.js:273:16)
at new BrowserRouter (C:\LMS-APP\node_modules\react-router-dom\modules\BrowserRouter.js:11:13)
at processChild (C:\LMS-APP\node_modules\react-dom\cjs\react-dom-server.node.development.js:2995:14)
at resolve (C:\LMS-APP\node_modules\react-dom\cjs\react-dom-server.node.development.js:2960:5)
at ReactDOMServerRenderer.render (C:\LMS-APP\node_modules\react-dom\cjs\react-dom-server.node.development.js:3435:22)
at ReactDOMServerRenderer.read (C:\LMS-APP\node_modules\react-dom\cjs\react-dom-server.node.development.js:3373:29)
at Object.renderToString (C:\LMS-APP\node_modules\react-dom\cjs\react-dom-server.node.development.js:3988:27)
at C:\LMS-APP\src\server\/server.js:10:40
at Layer.handle [as handle_request] (C:\LMS-APP\node_modules\express\lib\router\layer.js:95:5)

package.json


  "name": "LMS-APP",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": 
   "dev-server": "nodemon --exec babel-node src/server/server.js --ignore dist/",
   "dev-bundle": "webpack -w -d"
  ,
     "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": 
    "@babel/core": "^7.9.6",
    "@babel/node": "^7.8.7",
    "@babel/preset-env": "^7.9.6",
    "@babel/preset-react": "^7.9.4",
    "babel-loader": "^8.1.0",
    "express": "^4.17.1",
    "react": "^16.13.1",
    "react-dom": "^16.13.1",
    "react-router-dom": "^5.2.0",
    "webpack": "^4.43.0",
    "webpack-cli": "^3.3.11"
  ,
  "devDependencies": 
    "babel-eslint": "^10.1.0",
    "eslint": "^7.0.0",
    "eslint-plugin-react": "^7.20.0",
    "eslint-plugin-react-hooks": "^4.0.2",
    "nodemon": "^2.0.4"
  

【问题讨论】:

【参考方案1】:

由于您使用 express.js 作为服务器,我相信您还需要配置您的 server.js 代码。正如底部的错误日志告诉第一个被调用的文件是at C:\LMS-APP\src\server\/server.js:10:40

在此网站https://reacttraining.com/react-router/web/guides/server-rendering 中有一个“将所有内容放在一起”部分,您也可以在服务器端代码中遵循并实现正确的代码。由于您使用的是 express.js,因此请记住将其调整为您在 server.js 上的代码。

还要注意网站的代码示例。喜欢这个块:

const html = ReactDOMServer.renderToString(
      <StaticRouter location=req.url context=context>
        <App />
      </StaticRouter>
);

上面的代码 sn-p 将放在你的 server.js 文件中。

需要 React Router 的 &lt;StaticRouter&gt; 组件来解决有关“错误:不变失败:浏览器历史记录需要 DOM”的错误。

server.get("*", (req, res) => 
  // Render the component to a string.
  const html = ReactDOMServer.renderToString(    
    <StaticRouter location=req.url context=context>
      <App />
    </StaticRouter>

  );
  const finalDocument =`<html>
                          <head>
                            <title>Your App Title</title>
                          </head>
                          <body>
                            <div id="root">$html</div>
                          </body>
                         </html>
                        `;
    res.send(finalDocument);
  
);

这将是您的 server.get() 函数应具有的示例代码。服务器变量保存 express 应用程序。

如果错误仍然存​​在,您应该将 server.get() 函数中的第一个参数从 server.get("/", ....) 更改为 server.get("*", ....)

* 星号表示通配符,这意味着对服务器或默认 URL 的任何访问都将由您的服务器端处理,例如 GET http://localhost:&lt;port&gt;

【讨论】:

以上是关于服务器渲染-React Router Dom V^5.2.0 Error: Invariant failed: Browser history needs a DOM的主要内容,如果未能解决你的问题,请参考以下文章

React-router-dom 渲染道具没有返回任何组件

使用 react-router-dom 中的 Route 时 ReactDOM 渲染出错

如何添加将使用 react-router-dom 渲染组件的路由?

react-router-dom 开关在动态路径后不渲染组件

使用 react-router-dom 停止页面中侧边栏的重新渲染

react-router-dom v^4路由配置