在底部找到修改。
我一直在研究很多教程,甚至还有位于此处的反应训练服务器端渲染的文档:https://reacttraining.com/react-router/web/guides/server-rendering
对我来说有问题的是使用其他路由以获得完整的堆栈应用程序。例如,我们将使用MERN堆栈
(mongodb
express
React/Redux
nodejs
)。可以说我们在
app.js
喜欢这样:
app.use('/users', users);
app.use('/posts', posts);
并且我们的服务器端渲染设置与大多数这些教程一样,实际上我找不到一个没有以这种方式设置的,并且为了节省时间,我将把SSR代码放在哪里。如果您不知道如何进行SSR,那么请查看我上面给出的链接中的文档。我认为可能不需要它,但如果它让我知道,我可以添加一个简单的设置。
类似的东西:
app.get('*', (req, res) => { //server side rendering code here});
所以这里的问题是它遇到React Router 4
的每个路由和服务器端渲染内部,大多数人将使用matchRoutes
函数并传入他们用于反应方的路由。
好的,所以我已经解释了很多,但不是真正的问题所在:
问题:在反应方面,让我们说使用一个动作,我们将在这里使用axios作为一个简单的例子。
如果我这样做:
axios.get('/posts')
.then(response => {
console.log(response.data);
})
.catch(err => {
console.log(err);
});
这会遇到问题。对于任何熟悉快速和SSR的人,你都会知道原因。 app.get('*')
正在点击每条路线,或者更好地说明每条路线请求都会在这里通过,问题是当我们向/posts
发送请求时,会发生两种情况之一。
案例1:路由文件中有反应方的客户端路由/posts
,这种情况会将服务器端html作为response.data
返回,这显然是/posts
不是我们想要的。
案例2:路由文件中没有客户端路由/api/routename
用于反应方,此案例将返回404错误或类似于路由或页面未找到的情况正确设置你的SSR。
我需要一种能够使用我的后端的方法,但也能够使用SSR进行反应。
可能的解决方案?
使用某种类型的代理,并说app.get('*')
然后使用代理,这样就不会通过/users
推送您的电话。
或者某种方式只对单个路线进行SSR。
或排除某些路线,但能够使用所有客户端路线。我的意思是,如果我有客户端/users
和快速方/users
,我不希望客户端在我排除require('babel-core/register')({
presets: ['env', 'react', 'stage-0', 'stage-1']
});
const pkg_json = require('./package.json');
const vertex = require('vertex360')({ site_id: pkg_json.app });
var renderer = require('./renderer.js');
// initialize app
const app = vertex.app();
// import routes
const index = require('./routes/index');
const api = require('./routes/api');
const users = require('./routes/users');
// set routes
app.use('/api/users', users);
// hopefully will be used on every Route, this should handle SSR RR4
app.use(renderer);
module.exports = app;
时中断,但有些人仍然排除快递侧。
如果可能的话,我不完全确定怎么做这些解决方案,但我需要能够使用我的快速路线,而且我找不到具体方法如何做到,或者什么是最佳实践。
编辑:
服务器端app.js:
import React from 'react';
import { renderToString } from 'react-dom/server';
import { StaticRouter } from 'react-router-dom';
import { Provider } from 'react-redux';
import { renderRoutes } from 'react-router-config';
import serialize from 'serialize-javascript';
import { Helmet } from 'react-helmet';
import { matchRoutes } from 'react-router-config';
import routes from './src/routes';
import createStore from './src/stores';
function handleRender(req, res) {
const store = createStore.configure(null); // create Store in order to get data from redux
const promises = matchRoutes(routes, req.path)
.map(({ route }) => {
// Matches the route and loads data if loadData function is there
return route.loadData ? route.loadData(store) : null;
})
.map(promise => {
if (promise) {
return new Promise((resolve, reject) => {
promise.then(resolve).catch(resolve); // lets all data load even if route fails
});
}
});
Promise.all(promises).then(() => {
const context = {};
if (context.url) {
return res.redirect(301, context.url); // redirect for non auth users
}
if (context.notFound) {
res.status(404); // set status to 404 for unknown route
}
const content = renderToString(
<Provider store={store}>
<StaticRouter location={req.path} context={context}>
<div>{renderRoutes(routes)}</div>
</StaticRouter>
</Provider>
);
const initialState = serialize(store.getState());
const helmet = Helmet.renderStatic();
res.render('index', { content, initialState, helmet });
});
}
module.exports = handleRender;
renderer.js:
import React from 'react';
import { renderToString } from 'react-dom/server';
import { StaticRouter } from 'react-router-dom';
import { Provider } from 'react-redux';
import { renderRoutes } from 'react-router-config';
import serialize from 'serialize-javascript';
import { Helmet } from 'react-helmet';
import { matchRoutes } from 'react-router-config';
import routes from './src/routes';
import createStore from './src/stores';
function handleRender(req, res) {
const store = createStore.configure(null); // create Store in order to get data from redux
const promises = matchRoutes(routes, req.path)
.map(({ route }) => {
// Matches the route and loads data if loadData function is there
return route.loadData ? route.loadData(store) : null;
})
.map(promise => {
if (promise) {
return new Promise((resolve, reject) => {
promise.then(resolve).catch(resolve); // lets all data load even if route fails
});
}
});
Promise.all(promises).then(() => {
const context = {};
if (context.url) {
return res.redirect(301, context.url); // redirect for non auth users
}
if (context.notFound) {
res.status(404); // set status to 404 for unknown route
}
const content = renderToString(
<Provider store={store}>
<StaticRouter location={req.path} context={context}>
<div>{renderRoutes(routes)}</div>
</StaticRouter>
</Provider>
);
const initialState = serialize(store.getState());
const helmet = Helmet.renderStatic();
res.render('index', { content, initialState, helmet });
});
}
module.exports = handleRender;
反应切入点:
anchorPane.getChildren()
.filtered(node -> node instanceof TextField)
.forEach(node -> ((TextField)node).setText(""));
答案 0 :(得分:0)
感谢@VivekN,你这样做是为了确保你的
app.get('*')
位于每个声明的路线下方。这应该允许您的其他路线首先通过。