加载ReactJS页面时出现此错误
Error: Invariant failed: You should not use <Switch> outside a <Router>
at invariant (/home/user/Documents/Development/hmuweb/room/node_modules/tiny-invariant/dist/tiny-invariant.cjs.js:13:11)
at Object.children (/home/user/Documents/Development/hmuweb/room/node_modules/react-router/cjs/react-router.js:685:19)
at ReactDOMServerRenderer.render (/home/user/Documents/Development/hmuweb/room/node_modules/react-dom/cjs/react-dom-server.node.development.js:3635:55)
at ReactDOMServerRenderer.read (/home/user/Documents/Development/hmuweb/room/node_modules/react-dom/cjs/react-dom-server.node.development.js:3373:29)
at Object.renderToString (/home/user/Documents/Development/hmuweb/room/node_modules/react-dom/cjs/react-dom-server.node.development.js:3988:27)
at ./server/index.js.app.get (/home/user/Documents/Development/hmuweb/room/server-build/index.js:215:71)
at Layer.handle [as handle_request] (/home/user/Documents/Development/hmuweb/room/node_modules/express/lib/router/layer.js:95:5)
at next (/home/user/Documents/Development/hmuweb/room/node_modules/express/lib/router/route.js:137:13)
at Route.dispatch (/home/user/Documents/Development/hmuweb/room/node_modules/express/lib/router/route.js:112:3)
at Layer.handle [as handle_request] (/home/user/Documents/Development/hmuweb/room/node_modules/express/lib/router/layer.js:95:5)
我假设此错误消息来自我的App.js文件,但我似乎找不到确切发生错误的位置。我尝试重新构造App.js,但是当我这样做时,我收到另一个错误,说在路由器中将prop历史记录标记为必需,但其值未定义。同样,它无法读取未定义的属性“位置”。您知道如何解决此问题吗?它是在我实现SSR(服务器端渲染)时开始的。
import React, { Component } from 'react';
import { Route, Switch, BrowserRouter as Router } from 'react-router-dom';
import './App.css';
import Room from './App/pages/Room'
import Content from './App/pages/content';
class App extends Component {
render() {
return (
<div>
<Switch>
<Route exact={true} path="/" component={Room} />
<Route path="/watch" component={Content} />
</Switch>
</div>
);
}
}
export default App;
webpack.server.js文件,如果需要的话
const path = require('path');
const nodeExternals = require('webpack-node-externals');
module.exports = {
devtool: 'source-map',
entry: './server/index.js',
target: 'node',
externals: [nodeExternals()],
module: {
rules: [
{
test: /\.js$/,
use: ["babel-loader"],
exclude: /node_modules/,
},
{ test: /\.css$/, loader: "css-loader" },
{ test: /\.(jpg|png|svg)$/, use: 'file-loader'}
]
},
resolve: {
alias: {
'react-router-dom': path.join('./node_modules/react-router-dom')
}
},
output: {
path: path.resolve('server-build'),
filename: 'index.js'
},
};
package.json文件,以防万一
{
"name": "room",
"version": "0.1.0",
"private": true,
"dependencies": {
"@babel/plugin-proposal-class-properties": "^7.8.3",
"axios": "^0.19.2",
"babel-preset-es2015": "^6.24.1",
"bootstrap": "^3.4.1",
"branca": "^0.3.0",
"cors": "^2.8.5",
"express": "^4.17.1",
"hls.js": "^0.13.2",
"html-react-parser": "^0.10.3",
"jquery": "^3.5.1",
"jsonwebtoken": "^8.5.1",
"object-encrypt-decrypt": "^1.0.2",
"path": "^0.12.7",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-helmet": "^6.0.0",
"react-router-dom": "^5.2.0",
"react-router-redux": "^4.0.8",
"react-scripts": "3.2.0"
},
"scripts": {
"start": "node ./server/index.js | react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"dev:build-server": "NODE_ENV=development webpack --config webpack.server.js --mode=development -w",
"dev:start": "nodemon ./server-build/index.js",
"dev": "npm-run-all --parallel build dev:*"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"proxy": "http://localhost:5000",
"devDependencies": {
"babel-core": "^6.26.3",
"babel-preset-env": "^1.7.0",
"babel-preset-react-app": "^9.1.2",
"nodemon": "^2.0.4",
"npm-run-all": "^4.1.5",
"webpack-cli": "^3.3.11",
"webpack-node-externals": "^1.7.2"
},
"babel": {
"presets": [
"@babel/preset-env",
"@babel/preset-react"
],
"plugins": [
"@babel/plugin-proposal-class-properties"
]
}
}
Index.js
import path from 'path';
import fs from 'fs';
import express from 'express';
import React from 'react'
import ReactDOMServer from 'react-dom/server';
import { StaticRouter } from 'react-router-dom';
import App from '../src/App';
const PORT = process.env.PORT || 5000;
const app = express();
app.use(express.static(path.join(__dirname, '../build')));
app.get('/*', (req, res) => {
const context = {};
const app = ReactDOMServer.renderToString(
<StaticRouter location={req.url} context={context}>
<App />
</StaticRouter>
);
const indexFile = path.join(__dirname + '../build/index.html');
fs.readFile(indexFile, 'utf8', (err, data) => {
if (err) {
console.error('Something went wrong:', err);
return res.status(500).send('Oops, better luck next time!');
}
if (context.status === 404) {
res.status(404);
}
return res.send(
data.replace('<div id="root"></div>', `<div id="root">${app}</div>`)
);
});
});
app.listen(PORT, () => {
console.log(`? Server is listening on port ${PORT}`);
});
答案 0 :(得分:0)
经过数小时的故障排除,我终于解决了这个问题。
您不必将直接传递给renderToString函数,而必须将其嵌套在StaticRouter标记中。
这个答案帮助我:https://github.com/jaredpalmer/razzle/issues/1157#issuecomment-553044993
此外,我必须将Switch标签嵌套在Router标签内,如下所示:
<Router>
<Switch>
<Route exact={true} path="/" component={Room} />
<Route path="/watch" component={Content} />
</Switch>
</Router>
执行完此操作后,我收到另一个找不到我的构建index.html的问题。要解决此问题,我必须调整项目:
在ReactJS index.js文件中,我不得不将ReactDOM.render切换为ReactDOM.hydrate。
在服务器文件夹中创建了一个server.js文件,我在其中将index.js代码移入其中。
在旧服务器/index.js中,我使用@babel实现了对JSX的服务器端支持。
这是我的代码:
server / index.js
import path from 'path';
import fs from 'fs';
import express from 'express';
import React from 'react'
import ReactDOMServer from 'react-dom/server';
import { StaticRouter } from 'react-router-dom';
import App from '../src/App';
const PORT = process.env.PORT || 5000;
const app = express();
app.get('^/$', (req, res) => {
const context = {};
const app = ReactDOMServer.renderToString(
<StaticRouter location={req.url} context={context}>
<App />
</StaticRouter>
);
const indexFile = path.resolve('./build/index.html');
fs.readFile(indexFile, 'utf8', (err, data) => {
if (err) {
console.error('Something went wrong:', err);
return res.status(500).send('Oops, better luck next time!');
}
if (context.status === 404) {
res.status(404);
}
return res.send(
data.replace('<div id="root"></div>', `<div id="root">${app}</div>`)
);
});
});
app.use(express.static(path.resolve(__dirname, '..', 'build')));
app.listen(PORT, () => {
console.log(`? Server is listening on port ${PORT}`);
});
server / index.js
require('ignore-styles')
require('@babel/register')({
ignore: [/(node_module)/],
presets: ['@babel/preset-env', '@babel/preset-react'],
plugins: ['@babel/plugin-proposal-class-properties']
})
require('./server');
package.json
{
"name": "room",
"version": "0.1.0",
"private": true,
"homepage": "https://hmutv.com/",
"dependencies": {
"@babel/plugin-proposal-class-properties": "^7.8.3",
"@babel/preset-react": "^7.9.4",
"@babel/register": "^7.9.0",
"axios": "^0.19.2",
"babel-preset-es2015": "^6.24.1",
"bootstrap": "^3.4.1",
"branca": "^0.3.0",
"cors": "^2.8.5",
"express": "^4.17.1",
"history": "^4.10.1",
"hls.js": "^0.13.2",
"html-react-parser": "^0.10.3",
"ignore-styles": "^5.0.1",
"jquery": "^3.5.1",
"jsonwebtoken": "^8.5.1",
"next": "^9.4.0",
"object-encrypt-decrypt": "^1.0.2",
"path": "^0.12.7",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-helmet": "^6.0.0",
"react-router-dom": "^5.2.0",
"react-router-redux": "^4.0.8",
"react-scripts": "3.2.0"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"ssr": "node server/index.js"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"proxy": "http://localhost:5000",
"devDependencies": {
"babel-core": "^6.26.3",
"babel-preset-env": "^1.7.0",
"babel-preset-react-app": "^9.1.2",
"nodemon": "^2.0.4",
"npm-run-all": "^4.1.5",
"webpack-cli": "^3.3.11",
"webpack-node-externals": "^1.7.2"
}
}