我使用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来在actions文件中运行一个函数,该函数调用API并返回用户数据。无论我在哪里使用派遣,它都有相同的结果。在最佳条件下,React返回请求并等待来自其他服务器的数据。但由于我设置检查来自服务器的接收数据的条件,它不会返回任何内容。
我的组件
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;
}
})
}
}
答案 0 :(得分:0)
在render()
方法中调用dispatch是一种错误的做法,因为render方法应该是不可变的。使用redial
提供的挂钩包裹您的组件以解析数据apis。请参阅redial repo中的示例用法。
答案 1 :(得分:0)
最后,在反应服务器端渲染中渲染来自另一台服务器的数据的大量工作之后,我找到了最佳解决方案。 首先,你不需要重拨,这是多余的,至少在我的情况下。所以我从我的源代码中删除了它。 然后,我搬了
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解析promise,然后requireApiCall中的promise解析并返回回调“cb()”。路线开始渲染组件,发送到客户端的答案将使用接收的数据生成。
我知道这有点复杂,但效果很好。