Найдите внизу Edits.
Я действительно изучил множество руководств и даже документацию по рендерингу на стороне сервера для обучения реакции, расположенную здесь: 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
и передавать свои маршруты, которые они используют для стороны реагирования.
Итак, я многое объяснил, но не совсем в чем проблема:
ПРОБЛЕМА: когда на стороне реагирования, скажем, с помощью действия, и мы будем использовать аксиомы для простого примера здесь.
If I do:
axios.get('/posts')
.then(response => {
console.log(response.data);
})
.catch(err => {
console.log(err);
});
Это приводит к проблеме. И любой из вас, кто хорошо знает экспресс и SSR, поймет, почему. app.get('*')
затрагивает каждый маршрут или, другими словами, каждый запрос маршрута будет проходить здесь, проблема в том, что когда мы отправляем запрос на /posts
, происходит один из двух случаев.
Случай 1: в файле маршрутов для ответной стороны есть маршрут на стороне клиента /posts
, и в этом случае html на стороне сервера будет возвращен как response.data
, что явно не то, что нам нужно.
Случай 2: в файле маршрутов для ответной стороны нет маршрута на стороне клиента /posts
, и в этом случае будет возвращена ошибка 404 или что-то похожее на маршрут или страница не найдена, если вы правильно настроили SSR.
Мне нужен способ, чтобы иметь возможность использовать мой сервер, но также иметь возможность использовать SSR для реагирования.
Возможное решение?
Используйте какой-либо тип прокси и скажите, если
/api/routename
, то используйте прокси, чтобы ваши звонки не проходили черезapp.get('*')
.Или каким-то образом выполнять SSR только на отдельных маршрутах.
Или исключая определенные маршруты, но имея возможность использовать все маршруты на стороне клиента. В этом я имею в виду, что если у меня есть клиентская сторона
/users
и экспресс-сторона/users
, я не хочу, чтобы клиентская сторона ломалась, если я исключаю/users
, но каким-то образом все еще исключаю экспресс-сторону.
Я не совсем уверен, как реализовать эти решения, если они возможны, но мне нужно иметь возможность использовать мои экспресс-маршруты, и я не могу найти конкретного способа, как это сделать, или что лучше всего.
РЕДАКТИРОВАНИЕ:
серверная сторона app.js:
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;
рендерер.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;
Точка входа в реакцию:
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;
window is not defined
, когда я помещаю свои маршруты перед SSR всякий раз, когда я им звоню. - person Taylor Austin   schedule 13.11.2017