使用获取组件内部componentWillMount
不是一个正确的地方,以防您需要渲染服务器端。您需要以某种方式将其从组件中移出,并在获取实际数据后将其作为道具传递 - 例如,正如 @JakeSendar 在他的回答中所建议的那样。
我有一些使用 React 制作同构应用程序的经验,我面临的主要问题是如何等到所有数据加载完毕后再进行首次渲染
正如@FakeRainBrigand 在评论中已经提到的,不仅有一种方法可以做到这一点,而且这取决于您的要求。
构建同构应用程序的方法很少,从我的角度来看,一些有趣的是:https://github.com/webpack/react-starter https://github.com/webpack/react-starter and http://fluxible.io/ http://fluxible.io/
但是,正如我自己发现的,最优雅的方法是为 React 组件组织异步渲染,特别是使用 RxJS。
一般来说,我的申请结构如下:
- 视图 - 没有任何逻辑的 React 组件(只是一个视图)
-
models - 具有当前状态的可观察量(使用超级代理加载初始数据,然后与其他模型和/或操作结果相结合)。
在简单的情况下,它是这样的:
Rx.Observable.defer(fetchData).concat(updatesSubject).shareReplay()
-
操作(或意图) - 用于收集用户输入、执行某些操作并将操作结果分派给订阅者模型和/或其他操作的观察者。在简单的情况下,例如:
updatesSubject = new Rx.Subject();
action = new Rx.Subject();
action.switchMap(asyncRequest).subscribe(updatesSubject)
组件 - 由模型、其他组件和操作组合而成的 Observables(虚拟 DOM 元素流)(我对此有一个注释,解释了如何以及为何使用 RxJS 创建 Observable React 元素 https://gist.github.com/zxbodya/20c63681d45a049df3fc),现在我还计划添加部分组件(元组来自:react 组件、可观察对象、观察者和属性。部分使用 DI 填充)
路由器 - 负责处理位置更改的组件,
一般来说,主要功能是将位置更改映射到虚拟 DOM 元素和元信息流。但在细节上,在我的情况下有点复杂(url生成、活动url突出显示、导航时处理滚动,也有可能嵌套路由和多个视图)
所有这些都是使用 DI 容器组装在一起的,在我的例子中类似于angular2 DI 容器 https://github.com/angular/di.js,但针对我的特定需求进行了很多简化。
组件、模型和操作是使用 DI 创建的。
在服务器端应用程序是这样的:
var rootInjector = new Injector();
// setup server specific providers
rootInjector.provide(..., ...)
app.get('/*', function(req,res){
var injector = rootInjector.createChild();
// setup request specific providers
injector.provide(..., ...);
injector.get(Router)
.first()
.subscribe(function(routingResult){
res.render('app', {
title: routingResult.title,
content: React.renderToString(routingResult.content)
});
});
}
和客户端类似:
var rootInjector = new Injector();
// setup server specific providers
// actually this is omitted in my case because default providers are client side
rootInjector.provide(..., ...)
contentElement = document.getElementById('#content');
rootInjector.get(Router)
.subscribe(function(routingResult){
document.title = routingResult.title;
React.render(routingResult.content, contentElement)
});
与 Flux 相比,它是一种更具声明性且更强大的组织应用程序的方式。对于同构应用程序 - 对我来说,它看起来比各种使用 Flux 的黑客要好得多。但当然也有缺点...... - 它更复杂。
可能稍后,我将开源所有这些,但现在 - 它还没有准备好发布。
UPD1:
原始答案有点过时(稍后我计划更新它),并且我在这方面取得了一些进展。
上面提到的代码链接,已经开源:
- DI容器:di1 https://github.com/zxbodya/di1
- React 组件的容器(将视图连接到可观察对象和观察者):rx-反应容器 https://github.com/zxbodya/rx-react-container
- 入门模板,用于使用 RxJS 和 React 以及上面的库实现同构小部件:反应式小部件 https://github.com/zxbodya/reactive-widgets
关于完整的应用程序(工作仍在进行中,文档不太好,但总的来说应该很清楚):
- 专为同构反应式应用程序构建的路由器router1 https://github.com/zxbodya/router1并对组件进行反应以使用它router1-反应 https://github.com/zxbodya/router1-react
- 带有路由器和上述所有库的应用程序模板:router1-应用程序模板 https://github.com/zxbodya/router1-app-template