使用从 API 调用的数据响应服务器端渲染
React server side rendering using data called from API
我使用 react-redux + thunk + redial 并在服务器端生成我的 HTML。我想通过 react-helmet 使用来自另一台服务器的用户数据生成元标记。
在我的服务器中:
import { trigger } from 'redial';
trigger('fetch', components, locals)
.then(() => {
const state = getState();
var html = ReactDOMServer.renderToString (
<Provider store={store} key="provider">
<ReactRouter.RouterContext {...renderProps} />
</Provider>
);
let head = Helmet.rewind();
response.send(`<!DOCTYPE html>
<head>
<meta charSet="UTF-8"></meta>
<meta httpEquiv="X-UA-Compatible" content="IE=edge,chrome=1"></meta>
<meta name="viewport" content="width=device-width, initial-scale=1"></meta>
<link rel='stylesheet' href='/css/bootstrap.css'/>
${style? "<style>"+style+"</style>" : "<link rel='stylesheet' href='/css/app.css'/>"}
${head.title}
${head.meta}
${head.link}
${head.script}
</head>
<body>
<div id="app">${html}</div>
<script src='/javascript/bundle.js'></script>
${popUp}
</body>
</html>`);
在我的组件中,我在 render() 函数中调用 dispatch 到 运行 动作文件中的一个函数,该函数调用 API 和 returns 用户数据。无论我在哪里使用 dispatch,它都有相同的结果。在最好的情况下 React returns 请求并等待来自其他服务器的数据。但它 returns 由于我设置检查从服务器接收到的数据的条件,没有任何问题。
我的组件
var profile=[], shouldRender = false
export var Profile = React.createClass({
render () {
var {x,y,z} = this.props;
var pathArray = (this.props.path).split( '/' );
if(!canUseDOM && shouldRender == false)dispatch(
actions.theProfile(x,y,z)
).then((es) => {profile = es; shouldRender= true;Promise.resolve()})
.catch((et) => console.log("error"));
if(shouldRender){
console.log("got inside");
return (
<div className="container">
<RightSideBar page="profile"/>
<Helmet
title={metaData('title', name, profileId)}/>
<div className="col-md-6 col-xs-12 col-md-offset-3 content right">
<div className="row">
{profileContent(ideaTypes)}
</div>
</div>
<div className="col-md-3 col-xs-12 sidebar-left hidden-xs hidden-sm hidden-md">
<LeftSideBar page="profile"/>
</div>
</div>
)
}
});
以及我使用 axios
调用 API 的操作
export var viewingProfile = (ux,y,z) => {
return function (dispatch, getState) {
return axios.post(root + '/api/getUser', {
Id: x,
orgid: y,
profileId: z
})
.then(function (res) {
if(res.data.statusEntity.statusCode == -201){
window.location.href = "/user-not-found"
} else {
dispatch(updateState(res.data))
return res.data;
}
})
}
}
在 render()
方法中调用调度是错误的做法,因为渲染方法应该是不可变的。使用 redial
提供的钩子包装您的组件以解析数据 api。请参考 redial repo.
中的示例用法
最后,在对 react server-side 渲染中来自另一台服务器的渲染数据进行了大量工作之后,我找到了最佳解决方案。
首先,您不需要重拨,这是多余的,至少对我而言是这样。所以我把它从我的来源中删除了。
然后,我搬家了
dispatch(
actions.theProfile(x,y,z)
)
到我的路线
export default (store) => {
const requireApiCall= (nextState, replace, cb) => {
var state = store.getState();
return store.dispatch(actions.theProfile(x,y,z)).
then(()=>{
cb()
})
};
<Route path="/" component={App}>
<IndexRoute component={Home}/>
<Route path="profile" component={Profile } onEnter={requireApiCall}>
</Route>
</Route>
}
调度将执行,路由等待回调 "cb()",当我的 API 呼叫被接听时,我的商店会更新接收到的数据。然后 action 解决承诺,然后 requireApiCall 解决承诺和 returns 回调 "cb()"。路由开始呈现组件,发送给客户端的答案将使用接收到的数据生成。
我知道它有点复杂,但效果很好。
我使用 react-redux + thunk + redial 并在服务器端生成我的 HTML。我想通过 react-helmet 使用来自另一台服务器的用户数据生成元标记。 在我的服务器中:
import { trigger } from 'redial';
trigger('fetch', components, locals)
.then(() => {
const state = getState();
var html = ReactDOMServer.renderToString (
<Provider store={store} key="provider">
<ReactRouter.RouterContext {...renderProps} />
</Provider>
);
let head = Helmet.rewind();
response.send(`<!DOCTYPE html>
<head>
<meta charSet="UTF-8"></meta>
<meta httpEquiv="X-UA-Compatible" content="IE=edge,chrome=1"></meta>
<meta name="viewport" content="width=device-width, initial-scale=1"></meta>
<link rel='stylesheet' href='/css/bootstrap.css'/>
${style? "<style>"+style+"</style>" : "<link rel='stylesheet' href='/css/app.css'/>"}
${head.title}
${head.meta}
${head.link}
${head.script}
</head>
<body>
<div id="app">${html}</div>
<script src='/javascript/bundle.js'></script>
${popUp}
</body>
</html>`);
在我的组件中,我在 render() 函数中调用 dispatch 到 运行 动作文件中的一个函数,该函数调用 API 和 returns 用户数据。无论我在哪里使用 dispatch,它都有相同的结果。在最好的情况下 React returns 请求并等待来自其他服务器的数据。但它 returns 由于我设置检查从服务器接收到的数据的条件,没有任何问题。
我的组件
var profile=[], shouldRender = false
export var Profile = React.createClass({
render () {
var {x,y,z} = this.props;
var pathArray = (this.props.path).split( '/' );
if(!canUseDOM && shouldRender == false)dispatch(
actions.theProfile(x,y,z)
).then((es) => {profile = es; shouldRender= true;Promise.resolve()})
.catch((et) => console.log("error"));
if(shouldRender){
console.log("got inside");
return (
<div className="container">
<RightSideBar page="profile"/>
<Helmet
title={metaData('title', name, profileId)}/>
<div className="col-md-6 col-xs-12 col-md-offset-3 content right">
<div className="row">
{profileContent(ideaTypes)}
</div>
</div>
<div className="col-md-3 col-xs-12 sidebar-left hidden-xs hidden-sm hidden-md">
<LeftSideBar page="profile"/>
</div>
</div>
)
}
});
以及我使用 axios
调用 API 的操作 export var viewingProfile = (ux,y,z) => {
return function (dispatch, getState) {
return axios.post(root + '/api/getUser', {
Id: x,
orgid: y,
profileId: z
})
.then(function (res) {
if(res.data.statusEntity.statusCode == -201){
window.location.href = "/user-not-found"
} else {
dispatch(updateState(res.data))
return res.data;
}
})
}
}
在 render()
方法中调用调度是错误的做法,因为渲染方法应该是不可变的。使用 redial
提供的钩子包装您的组件以解析数据 api。请参考 redial repo.
最后,在对 react server-side 渲染中来自另一台服务器的渲染数据进行了大量工作之后,我找到了最佳解决方案。 首先,您不需要重拨,这是多余的,至少对我而言是这样。所以我把它从我的来源中删除了。 然后,我搬家了
dispatch(
actions.theProfile(x,y,z)
)
到我的路线
export default (store) => {
const requireApiCall= (nextState, replace, cb) => {
var state = store.getState();
return store.dispatch(actions.theProfile(x,y,z)).
then(()=>{
cb()
})
};
<Route path="/" component={App}>
<IndexRoute component={Home}/>
<Route path="profile" component={Profile } onEnter={requireApiCall}>
</Route>
</Route>
}
调度将执行,路由等待回调 "cb()",当我的 API 呼叫被接听时,我的商店会更新接收到的数据。然后 action 解决承诺,然后 requireApiCall 解决承诺和 returns 回调 "cb()"。路由开始呈现组件,发送给客户端的答案将使用接收到的数据生成。
我知道它有点复杂,但效果很好。