我正在尝试在我的反应应用程序中实现服务器端呈现。我无法通过react,react-dom和react-router的服务器实现来访问DOM。我有或者#34;浏览器历史需要一个DOM"错误。
所以我的猜测是我在服务器或客户端包装组件的方式有问题。
我将分享本练习中涉及的结构和重要文件!
server.js
import React from 'react';
import { renderToString } from 'react-dom/server';
// import { StaticRouter } from 'react-router';
import {StaticRouter} from 'react-router-dom';
import createBrowserHistory from 'history/createBrowserHistory';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import { ConnectedRouter, routerMiddleware } from 'react-router-
redux';
import { multiClientMiddleware } from 'redux-axios-middleware';
import api from "../src/actions/api";
import rootReducer from "../src/reducers/index";
import routes from '../src/routes/routes';
const app = express();
app.use(express.static('public'));
app.get('*', (req,res)=>{
const axiosMiddlewareOptions = {
interceptors: {
request: [
(action, config) => {
if (sessionStorage.token) {
config.headers['Authorization'] = 'Token '+ sessionStorage.token;
}
return config
}
]
}
};
const history = createBrowserHistory();
const appRouterMiddleware = routerMiddleware(history);
const createStoreWithMiddleware =
applyMiddleware(multiClientMiddleware(api, axiosMiddlewareOptions),
appRouterMiddleware)(createStore);
const store = createStoreWithMiddleware(rootReducer, {},
window.devToolsExtension ? window.devToolsExtension() : f => f);
const context = {};
const html = renderToString(
<Provider store={store}>
<StaticRouter location={req.url} context={context}>
<ConnectedRouter history={history} children={routes}/>
</StaticRouter>
</Provider>
);
res.send(`
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
<base href="/"/>
<link href="assets/img/favikin-hw.png" rel="shortcut
icon" type="image/x-icon" />
<meta name="viewport" content=" width=device-width,
maximum-scale=1">
</head>
<body>
<div class="wrapper">${html}</div>
</body>
</html>
`)
});
app.listen(process.env.PORT || 8080, ()=>{
console.log('Server is Listening')
});
index.js
import React from 'react';
import { render } from 'react-dom';
import createBrowserHistory from 'history/createBrowserHistory';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import { ConnectedRouter, routerMiddleware } from 'react-router-redux';
import { multiClientMiddleware } from 'redux-axios-middleware';
import api from "./actions/api";
import rootReducer from "./reducers/index";
import routes from './routes/routes';
import { BrowserRouter } from 'react-router-dom';
import '../assets/css/bootstrap.min.css';
import '../assets/style.css';
import '../node_modules/react-datetime/css/react-datetime.css';
import '../node_modules/react-select/dist/react-select.min.css';
const axiosMiddlewareOptions = {
interceptors: {
request: [
(action, config) => {
if (sessionStorage.token) {
config.headers['Authorization'] = 'Token '+ sessionStorage.token;
}
return config
}
]
}
};
const history = createBrowserHistory();
const appRouterMiddleware = routerMiddleware(history);
const createStoreWithMiddleware = applyMiddleware(multiClientMiddleware(api, axiosMiddlewareOptions), appRouterMiddleware)(createStore);
const store = createStoreWithMiddleware(rootReducer, {}, window.devToolsExtension ? window.devToolsExtension() : f => f);
render(
<Provider store={store}>
<ConnectedRouter history={history} children={routes}/>
</Provider>,
document.querySelector('.wrapper'));
App.js
import React, { Component, PropTypes } from "react";
import Header from '../components/Header/Header';
import Footer from '../components/Footer/Footer';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
class App extends Component {
render() {
return (
<MuiThemeProvider>
<div className="wrapper-box">
<div className="inner-wrapper">
<Header/>
{this.props.children}
</div>
<Footer/>
</div>
</MuiThemeProvider>
);
}
}
App.propTypes = {
children: PropTypes.object.isRequired
};
export default App;
routes.js
import React from 'react';
import App from '../containers/App';
import {
Route,
Switch
} from 'react-router-dom';
import MainPage from '../containers/MainPage/MainPage';
import DetailPage from '../components/DetailPage/DetailPage';
import AboutProject from '../containers/AboutProject/AboutProject';
import Contacts from '../containers/Contacts/Contacts';
import SectionPage from '../containers/SectionPage/SectionPage';
import SearchPage from '../containers/SearchPage/SearchPage';
import NoMatch from '../containers/NoMatch/NoMatch';
export default (
<App>
<div>
<Switch>
<Route exact={true} path='/' component={MainPage} />
<Route path='/about_the_project' component={AboutProject} />
<Route path='/contacts' component={Contacts} />
<Route path="/search-results/:category/:term" component={SearchPage}/>
<Route exact={true} path='/:name' component={SectionPage} />
<Route path="/articles/:slug" component={DetailPage}/>
<Route path="/events/:slug" component={DetailPage}/>
<Route path="/news/:slug" component={DetailPage}/>
<Route path="/interviews/:slug" component={DetailPage}/>
<Route path="/technologies/:slug" component={DetailPage}/>
<Route path='*' component={NoMatch}/>
</Switch>
</div>
</App>
)
答案 0 :(得分:0)
我还没来得及测试它,但ConnectRouter有一个名为isSSR的道具,它可以阻止订阅仅限DOM的东西。 (https://github.com/ReactTraining/react-router/blob/master/packages/react-router-redux/modules/ConnectedRouter.js)
我猜您现在可以使用memoryHistory
。 (https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/api/history.md)
将尝试在周末获得一个示例应用程序。
答案 1 :(得分:0)
使用createMemoryHistory()
解决了错误const history = createMemoryHistory();