我相信这个问题的正确描述是用timdorr解释这里的。我尝试从包中导出App.js,但得到了未定义的窗口错误。所以还是被困住了
SSR/Client为我反应路由器Dom“开关”中断与“不变失败”。我相信它说这与“路由器”之外不允许的开关有关,因为它是在“路由器”内部。
下面是最低限度的项目链接,这可能更容易查看项目。我已经列出了下面的主要文件
1:服务器端呈现端点
// EXPRESS ROUTER
const express = require("express");
const aRouter = express.Router();
// REACT UTILITIES
import React from "react";
import { renderToNodeStream } from "react-dom/server";
import { StaticRouter } from "react-router-dom";
import { createMemoryHistory } from "history";
import Loadable from "react-loadable";
// REDUX UTILITIES
import { init } from "../src/module/store";
import { Provider } from "react-redux";
// CUSTOM COMPONENTS
import App from "../src/App";
// UTILITIES
import fs from "fs-extra";
import renderUtils from "../utils/renderUtils";
// ASSETS
import { initState } from "../assets/store/init";
aRouter.get(["/", "/home"], async function (req, res) {
console.log("RENDER HOME");
try {
// INITIAL WRITE TO CLIENT - START HEAD
res.setHeader('Content-Type', 'text/html');
res.write("<!DOCTYPE html>");
res.write("<html style='scrollbar-width: none;'>");
let headHTML = await fs.readFile("./public/head.html", "utf-8");
let scriptsHTML = await fs.readFile("./public/scripts.html", "utf-8");
res.write(headHTML);
res.write("<body>");
res.write(`<div id = "app-container">`);
// INITALISING STATE
var initialState = initState();
initialState.article.articles = {
"abcde": {
title: "My First Article",
body: "This is my first article"
},
"fghij": {
title: "My Second Article",
body: "This is my second article"
},
"klmno": {
title: "My Third Article",
body: "This is my third article"
}
};
initialState.article.fetched = true;
initialState.ui.user = { type: "" };
initialState.ui.global = {
team: "Arsenal",
teamID: 19
};
const history = createMemoryHistory({ initialEntries: [req.originalUrl] });
const store = init(history, initialState);
// THE ISSUE SEEMS TO BE TO DO WITH THIS SERVER SIDE STATIC BROWSER AND THE CLIENT BORWSER ROUTER
const stream = renderToNodeStream(
<Provider store = {store}>
<StaticRouter history = {history} location = {req.originalUrl} context = {{}}>
<App />
</StaticRouter>
</Provider>
);
stream.pipe(res, { end: false });
stream.on("end", renderUtils.onRenderEnd.bind(this, res, store, scriptsHTML));
} catch (err) { renderUtils.onRenderError.bind(this, res, "RENDER HOME ERROR", err.message); }
});
var self = (module.exports = aRouter);2:客户索引
// REACT
import React from "react";
import ReactDOM from "react-dom";
import Loadable from "react-loadable";
import { BrowserRouter } from "react-router-dom";
import { createMemoryHistory } from "history";
import { Provider } from "react-redux";
// REDUX
import { init } from "./module/store";
// CREATE STORE
let history = createMemoryHistory();
let store = init(history, window.INITIAL_STATE);
// MAIN APP COMPONENT
import App from "./App";
// MOUNTED STYLES
import "./style/client/index.scss";
const renderApp = () => {
ReactDOM.hydrate(
<Provider store = {store}>
<BrowserRouter history = {history}>
<App />
</BrowserRouter>
</Provider>,
document.getElementById("app-container")
);
};
store.subscribe(() => renderApp());3:应用-客户端
// REACT
import React, { PureComponent } from "react";
import { Switch, Route } from "react-router-dom";
import PropTypes from "prop-types";
// REDUX STORE
import { connect } from "react-redux";
import { getName, getAge, getPosition } from "./module/user/userReducer";
import { getUIElement, setUIElement } from "./module/uiReducer";
// IMPORT CUSTOM COMPONENTS
import Routes from "./Routes";
class App extends PureComponent {
componentDidMount = () => this.props.setUI("user", "type", "admin");
render = () => {
return (
<div className = "app">
<span>My App</span>
<span>Name : {this.props.name}</span>
<span>Age : {this.props.age}</span>
<span>Position : {this.props.position}</span>
<span>Team : {this.props.team}</span>
<span>Team ID : {this.props.teamID}</span>
<span>Type : {this.props.type}</span>
<div>
<Switch>
<Route path = "/" component = {MyLocation} />
<Route path = "/contact" render = {() => (<MyLocation location = "Contact" />)} />
</Switch>
</div>
</div>
);
};
};
App.propTypes = {
name: PropTypes.string.isRequired,
age: PropTypes.number.isRequired,
position: PropTypes.string.isRequired,
team: PropTypes.string.isRequired,
teamID: PropTypes.number.isRequired,
type: PropTypes.string.isRequired,
setUI: PropTypes.func.isRequired
};
const mapStateToProps = state => ({
name: getName(state),
age: getAge(state),
position: getPosition(state),
team: getUIElement(state, "global", "team"),
teamID: getUIElement(state, "global", "teamID"),
type: getUIElement(state, "user", "type")
});
const mapDispatchToProps = dispatch => ({
setUI: (component, element, value) => dispatch(setUIElement({ component, element, value }))
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(App);完全最小反应应用程序这里
当我添加开关和路由时,它就会中断。开关“在”浏览器路由器内。我读过一些文章,解释如何向客户端发送相同的React,但我尝试了解释,但它们对我不起作用。
要运行该项目,只需运行“纱线”、"npm运行生成“和"npm启动”。这个应用程序只有一个页面,上面有一些填充文本。
问题:开关中断要求:尝试开关工作:解释从服务器端向客户端带来相同的反应路由器的解释和使用webpack的说明等。
Timdorr (在问题开始时分享)解释了这一点。
我们在5.0中使用了一个新的React.createContext API来替换遗留的上下文使用。这涉及到创建一个“上下文”对、一组提供者和消费者组件。我们在一个直接导入到路由器和链接中的单例模块中创建它。在这个新API中,您必须使用完全相同的实例。两个单独创建的上下文将永远不会匹配,也不会彼此可见。
有趣的是,这部作品生活在Heroku的“生产”上,但在当地却不起作用。我想heroku有一些后备代码来捕捉它。
任何帮助都是伟大的;
丹尼尔
发布于 2021-12-15 14:05:10
在玩了很多次之后,我发现这个问题源于
import { withRouter } from "react-router-dom";
export default withRouter(Component);我认为withRouter在这个新版本上已经不存在了,至于它为什么与Heroku一起工作是个谜。我认为Heroku有很好的版本控制和调试/处理功能。
我开始使用钩子useHistory,并将我的经典组件转换为带有钩子的函数组件,现在一切都好了。
丹尼尔
https://stackoverflow.com/questions/64344024
复制相似问题