如何在反应服务器端渲染中添加其他快速路由以用作后端

时间:2017-11-10 15:18:43

标签: reactjs express redux serverside-rendering react-router-dom

在底部找到修改

我一直在研究很多教程,甚至还有位于此处的反应训练服务器端渲染的文档: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进行反应。

可能的解决方案?

  1. 使用某种类型的代理,并说app.get('*')然后使用代理,这样就不会通过/users推送您的电话。

  2. 或者某种方式只对单个路线进行SSR。

  3. 或排除某些路线,但能够使用所有客户端路线。我的意思是,如果我有客户端/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; 时中断,但有些人仍然排除快递侧。

  4. 如果可能的话,我不完全确定怎么做这些解决方案,但我需要能够使用我的快速路线,而且我找不到具体方法如何做到,或者什么是最佳实践。

    编辑:

    服务器端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(""));
    

1 个答案:

答案 0 :(得分:0)

感谢@VivekN,你这样做是为了确保你的 app.get('*')位于每个声明的路线下方。这应该允许您的其他路线首先通过。