服务器端未定义的renderProps / React / React-Router + Node / Express.js的同构渲染
我试图得到服务器端/同构渲染工作的反应应用程序与反应路由器一致。
我的route.js
:
import React from 'react'; import { Route } from 'react-router'; import Test from './components/test'; export default ( <Route path="/test" component={ Test }> </Route> );
我的server.js
:
'use strict'; require('babel-core/register') var path = require('path'); var express = require('express'); var logger = require('morgan'); var compression = require('compression'); var http = require('http'); var ReactDOM = require('react-dom/server'); var Router = require('react-router'); var match = Router.match; var RoutingContext = Router.RoutingContext; var routes = require('./src/routes'); var app = express(); var server; var PORT = process.env.PORT || 3000 app.use(logger('dev')); app.use(compression()); // Set path to public assets app.use(express.static(path.join(__dirname, 'public'))); app.get('*', function(req, res) { console.log('URL: ', req.url); console.log('Routes: ', routes); match({ routes: routes, location: req.url }, (error, redirectLocation, renderProps) => { console.log('Render Props: ', renderProps) if (error) { res.status(500).send(error.message) } else if (redirectLocation) { res.redirect(302, redirectLocation.pathname + redirectLocation.search); } else if (renderProps) { res.status(200).send(ReactDOM.renderToString(React.createElement(RoutingContext, renderProps))) } else { res.status(404).send('Not found') } }) }) server = http.createServer(app); server.listen('3000', () => { console.log('Express server listening on port ' + PORT); });
所以当我运行npm run start时,只需在server.js
上调用node
即可。 服务器启动正常,但所有的请求,包括/test
回来为404s。
我console.log'd req.url,它正在返回正确的url。 我对“路由”文件做了相同的处理,并且确实find了正确的文件。 以下是这些日志的输出:
Express server listening on port 3000 URL: /test Routes: { default: { '$$typeof': Symbol(react.element), type: { [Function] displayName: 'Route', createRouteFromReactElement: [Function: createRouteFromReactElement], propTypes: [Object] }, key: null, ref: null, props: { path: '/test', component: [Object] }, _owner: null, _store: {} } } Render Props: undefined GET /test 404 19.596 ms - 9
然而, renderProps
总是未定义的,并且响应返回404.我认为我正确地遵循了这些示例,但是我不确定哪里出错了。
经过长时间的debugging,我遇到了类似的问题,我发现了一些可以解决这个问题的东西,下面是我在应用程序中改变的几点:
i)首先你的testing组件应该返回一个适当的dom元素,它可以渲染,而不是只渲染组件。 您应该返回null或包含所需元素的正确容器元素。请参见下面的示例(这是我在应用程序中执行的第一个错误)。
export default class Test extends React.Component { constructor(props) { super(props); } render () { return ( <div> <h1>opopooopppopo</h1> <p>This is your world.</p> </div> ); } }
ii)在你的代码库中使用RouterContext而不是使用RoutingContext ,这是我的工作,这是我的代码中的主要问题。 因为RoutingContext已经在新版本的react-router中被弃用了。 这个改变解决了我的问题。
res.status('200').send(ReactDOM.renderToString(<RouterContext {...renderProps}/>));
(注意:请不要忘记从react-router模块导入RouterContext。)
//从react-router导入路由器上下文的语句
var RouterContext = Router.RouterContext;
iii)如果以上所有的东西都不起作用 ,那么改变匹配函数使用routes.default而不是仅路由 。 改变:匹配({routes:routes,location}匹配({routes:routes.default,location} ,如果你使用的是babel 6,这个改变是必须的。试试这个结合RoutingContext和RouterContext,因为我不知道版本的react-router和babel是你使用的,所以组合是:
a)匹配({routes: routes })与res.status('200')的组合。
b)match({routes: routes })与res.status('200')的组合。send(ReactDOM.renderToString(< RouterContext {… renderProps} />));
c)match({routes: routes.default })与res.status('200')的组合。send(ReactDOM.renderToString(< RoutingContext {… renderProps} />));
d)match({routes: routes.default })与res.status('200')的组合。