React-route 和服务端渲染——如何用数据渲染组件
React-route and server-side rendering - how to render components with data
当在服务器端呈现它们时,我已经能够传递数据以对组件做出反应,例如:
app.get('/', function (req, res, next) {
var reactHtml = ReactDOMServer.renderToString(component({data}));
res.render('index.jade', {reactOutput: reactHtml});
});
现在改成
server.js:
app.get('*', (req, res) => {
// match the routes to the url
match({ routes: routes, location: req.url }, (err, redirect, props) => {
props.data = {q:123};
const appHtml = ReactDOMServer.renderToString(routerContext(props));
res.render('index.jade', {reactOutput: appHtml});
})
});
路由器上下文
module.exports = React.createClass({
render: function(){return(<RouterContext {...this.props} />)}
});
和路线
module.exports = (
<Route path="/" component={App} {...this.props}>
<IndexRoute component={List}/>
<Route path="/about" component={About}/>
</Route>
);
App.jsx
var App = React.createClass({
render: function () {
console.log(this.props);
return (
<div id="app-root" className="container">
<Nav/>
<h1>{this.props.q}</h1>
{this.props.children}
<div className="Row">
<div className="footer col-lg-12"></div>
</div>
</div>
)
}
});
例如,我想在我的 App 组件中从这一点 props.data = {q:123};
获取数据,但是当我在 App 组件渲染方法中执行 console.log(this.data);
时,我有历史、位置等,但不是我的数据。无论如何,是否可以将数据 {q:123}
从 server.js 逻辑传递到组件(App 或 List 或 About)道具?
(假设我们现在总是加载一些数据)
您需要序列化您的数据并将其添加到服务器呈现的页面,例如,如果您将其作为 initialState
:
传递给您的根组件
renderInitialState() {
const innerHtml = `window.__INITIAL_STATE__ = ${JSON.stringify(this.props.initialState)}`;
return <script dangerouslySetInnerHTML={{__html: innerHtml}} />;
}
所以:
<script>window.__INITIAL_STATE__ = JSON.stringify(yourObject);</script>
请注意,您似乎使用 jade 来呈现 "shell" 而不是 React。同样的事情适用于玉模板。
您通常会在 <body>
的底部呈现它(但在您的应用程序 js 脚本之上)。
如果您正在为您的客户端状态使用 flux,您将在创建商店时传递此对象,例如对于 redux:
const store = configureStore(window.__INITIAL_STATE__);
你的 props.data = {q:123};
不会在任何地方被调用,因为 RouterContext 不知道如何处理它。
您传递给 match
的回调函数的三个参数是:
- 错误:如果发生错误,则为 javascript 错误对象,否则为
undefined
。
- redirectLocation:如果路由是重定向,则为
Location
对象,
undefined
否则
renderProps:如果路由匹配,你应该传递给路由上下文的道具,undefined
否则。
如果三个参数都是undefined
,这意味着没有找到匹配的路由
给定位置。
要了解该机制,您可以在此处添加 console.dir
match({ routes: routes, location: req.url }, (err, redirect, props) => {
console.dir(props);
const appHtml = ReactDOMServer.renderToString(routerContext(props));
res.render('index.jade', {reactOutput: appHtml});
})
});
而 console.dir(props.components)
会向您显示所有传递给渲染的组件。您还可以在此处创建一个新的反应元素并将其推送到 props.components
将数据传递到您的应用程序组件 没有商店
修改此函数使其能够检索数据,并使用新数据创建虚拟组件
routes.jsx
module.exports = function(serverData){
var Dummy= React.createClass({
render: function () {
return (
<div> customProps=serverData </div>
);}
});
return(
<Route path="/" component={App}>
<Route path='data' component={{PonyMan: Dummy}}
<IndexRoute component={List}/>
<Route path="/about" component={About}/>
</Route>
);
}
server.jsx:
app.get('*', (req, res) => {
myCustomData = 'I like ponies'
const routes = createRoutes(myCustomData); //from imported routes.jsx
match({ routes: routes, location: req.url }, (err, redirect, props) => {
const appHtml = ReactDOMServer.renderToString(routerContext(props));
res.render('index.jade', {reactOutput: appHtml});
})
});
App.js
var App = React.createClass({
render: function () {
return (
<div id="app-root" className="container">
<Nav/>
<h1>{this.props.main}</h1>//this now shows <div>I Like Ponies</div>
//this can still display other routes
{this.props.children}
<div className="Row">
<div className="footer col-lg-12"></div>
</div>
</div>
)
}
});
P.S。使用 redux 商店会更容易
检查此项目以查看具有服务器端渲染的 react-router redux express mongoose 项目的一个很好的示例
https://github.com/choonkending/react-webpack-node
当在服务器端呈现它们时,我已经能够传递数据以对组件做出反应,例如:
app.get('/', function (req, res, next) {
var reactHtml = ReactDOMServer.renderToString(component({data}));
res.render('index.jade', {reactOutput: reactHtml});
});
现在改成
server.js:
app.get('*', (req, res) => {
// match the routes to the url
match({ routes: routes, location: req.url }, (err, redirect, props) => {
props.data = {q:123};
const appHtml = ReactDOMServer.renderToString(routerContext(props));
res.render('index.jade', {reactOutput: appHtml});
})
});
路由器上下文
module.exports = React.createClass({
render: function(){return(<RouterContext {...this.props} />)}
});
和路线
module.exports = (
<Route path="/" component={App} {...this.props}>
<IndexRoute component={List}/>
<Route path="/about" component={About}/>
</Route>
);
App.jsx
var App = React.createClass({
render: function () {
console.log(this.props);
return (
<div id="app-root" className="container">
<Nav/>
<h1>{this.props.q}</h1>
{this.props.children}
<div className="Row">
<div className="footer col-lg-12"></div>
</div>
</div>
)
}
});
例如,我想在我的 App 组件中从这一点 props.data = {q:123};
获取数据,但是当我在 App 组件渲染方法中执行 console.log(this.data);
时,我有历史、位置等,但不是我的数据。无论如何,是否可以将数据 {q:123}
从 server.js 逻辑传递到组件(App 或 List 或 About)道具?
(假设我们现在总是加载一些数据)
您需要序列化您的数据并将其添加到服务器呈现的页面,例如,如果您将其作为 initialState
:
renderInitialState() {
const innerHtml = `window.__INITIAL_STATE__ = ${JSON.stringify(this.props.initialState)}`;
return <script dangerouslySetInnerHTML={{__html: innerHtml}} />;
}
所以:
<script>window.__INITIAL_STATE__ = JSON.stringify(yourObject);</script>
请注意,您似乎使用 jade 来呈现 "shell" 而不是 React。同样的事情适用于玉模板。
您通常会在 <body>
的底部呈现它(但在您的应用程序 js 脚本之上)。
如果您正在为您的客户端状态使用 flux,您将在创建商店时传递此对象,例如对于 redux:
const store = configureStore(window.__INITIAL_STATE__);
你的 props.data = {q:123};
不会在任何地方被调用,因为 RouterContext 不知道如何处理它。
您传递给 match
的回调函数的三个参数是:
- 错误:如果发生错误,则为 javascript 错误对象,否则为
undefined
。 - redirectLocation:如果路由是重定向,则为
Location
对象,undefined
否则 renderProps:如果路由匹配,你应该传递给路由上下文的道具,
undefined
否则。如果三个参数都是
undefined
,这意味着没有找到匹配的路由 给定位置。
要了解该机制,您可以在此处添加 console.dir
match({ routes: routes, location: req.url }, (err, redirect, props) => {
console.dir(props);
const appHtml = ReactDOMServer.renderToString(routerContext(props));
res.render('index.jade', {reactOutput: appHtml});
})
});
而 console.dir(props.components)
会向您显示所有传递给渲染的组件。您还可以在此处创建一个新的反应元素并将其推送到 props.components
将数据传递到您的应用程序组件 没有商店
修改此函数使其能够检索数据,并使用新数据创建虚拟组件
routes.jsx
module.exports = function(serverData){
var Dummy= React.createClass({
render: function () {
return (
<div> customProps=serverData </div>
);}
});
return(
<Route path="/" component={App}>
<Route path='data' component={{PonyMan: Dummy}}
<IndexRoute component={List}/>
<Route path="/about" component={About}/>
</Route>
);
}
server.jsx:
app.get('*', (req, res) => {
myCustomData = 'I like ponies'
const routes = createRoutes(myCustomData); //from imported routes.jsx
match({ routes: routes, location: req.url }, (err, redirect, props) => {
const appHtml = ReactDOMServer.renderToString(routerContext(props));
res.render('index.jade', {reactOutput: appHtml});
})
});
App.js
var App = React.createClass({
render: function () {
return (
<div id="app-root" className="container">
<Nav/>
<h1>{this.props.main}</h1>//this now shows <div>I Like Ponies</div>
//this can still display other routes
{this.props.children}
<div className="Row">
<div className="footer col-lg-12"></div>
</div>
</div>
)
}
});
P.S。使用 redux 商店会更容易 检查此项目以查看具有服务器端渲染的 react-router redux express mongoose 项目的一个很好的示例 https://github.com/choonkending/react-webpack-node