通常,当客户端请求一个包含React组件页面的时候,服务端首先响应输出这个页面,客户端和服务端有了第一次交互。然后,如果加载组件的过程需要向服务端发出Ajax请求等,客户端和服务端又进行了一次交互,这样,耗时相对较长。服务端是否可以在页面初次加载时把所有方面渲染好再一次性响应给客户端呢?

「React同构直出」就是用来解决这个问题的,做到「秒开」页面。过程大致是这样滴:

1、在需要同构直出的页面(比如是index.html)放上占位符

  1. <div id="root">@@@</div>
  2. ###

以上,当客户端发出首次请求,服务端渲染出组件的html内容放@@@这个位置,然后服务端再渲染出类似<script>renderApp()</script>这样的js代码段把组件最终渲染到DOM上。也就是说,renderApp方法实际上就是在渲染组件。

2、而为了直接调用renderApp方法,必须让renderApp方法成为window下的方法

  1. window.renderApp = function(){ReactDOM.render(...)}

3、服务端取出index.html,渲染出占位符的内容,替代占位符,并一次性响应给客户端

通过一个例子来体会。

文件结构

  1. browser.js(在这里把渲染组件的过程赋值给window.renderApp)
  2. bundle.js(把browser.js内容bundle到这里)
  3. Component.js(组件在这里定义)
  4. express.js(服务端)
  5. index.html(同构直出的页面)
  6. package.json

index.html,直出页面放上占位符

  1. <!doctype html>
  2. <html>
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Untitled Document</title>
  6. </head>
  7. <body>
  8. <div id="root">@@@</div>
  9. <script src="bundle.js"></script>
  10. ###
  11. </body>
  12. </html>

Component.js,在这里定义组件

  1. var React = require('react');
  2. var ReactDOM = require('react-dom');
  3. var Component = React.createClass({
  4. clickHandler: function(){
  5. alert(this.props.msg)
  6. },
  7. render: function(){
  8. return React.createElement('button', {onClick: this.clickHandler}, this.props.msg)
  9. }
  10. })
  11. module.exports = Component;

browser.js,把组件渲染过程赋值给window对象

  1. var React = require('react');
  2. var ReactDOM = require('react-dom');
  3. var Component = React.createFactory(require('./Component'));
  4. window.renderApp = function(msg){
  5. ReactDOM.render(Component({msg: msg}), document.getElementById('root'));
  6. }

可以通过<script>render()</script>来触发组件的渲染。稍后,在服务端会把这段代码渲染出来。

express.js,服务端

以上,需要直出的页面有了占位符,定义了组件,并把渲染组件的过程赋值给了window对象,服务端现在要做的工作就是:生成组件的html和渲染组件的js,放到直出页面index.html的占位符位置。

  1. var express = require('express');
  2. var React = require('react');
  3. var ReactDOMServer = require('react-dom/server');
  4. var fs = require('fs');
  5. var Component = React.createFactory(require('./Component'));
  6. //原先把文件读出来
  7. var BUNDLE = fs.readFileSync('./bundle.js',{encoding:'utf8'});
  8. var TEMPLATE = fs.readFileSync('./index.html',{encoding:'utf8'});
  9. var app = express();
  10. function home(req, res){
  11. var msg = req.params.msg || 'Hello';
  12. var comp = Component({msg: msg});
  13. //@@@占位符的地方放组件
  14. var page = TEMPLATE.replace('@@@', ReactDOMServer.renderToString(comp));
  15. //###占位符的地方放js
  16. page = page.replace('###', '<script>renderApp("'+msg+'")</script>')
  17. res.send(page);
  18. }
  19. //路由
  20. app.get('', home);
  21. app.get('/bundle.js', function(req, res){
  22. res.send(BUNDLE);
  23. })
  24. app.get('/:msg', home);
  25. app.listen(4000);

package.json中的配置

  1. "scripts": {
  2. "start": "watchify ./browser.js -o ./bundle.js"
  3. },

运行:npm start

运行:node express.js

浏览:localhost:4000

项目地址:https://github.com/darrenji/ReactIsomorphicSimpleExample

React同构直出原理浅析的更多相关文章

  1. 腾讯新闻构建高性能的 react 同构直出方案

    在腾讯新闻抢金达人活动 node 同构直出渲染方案的总结文章中我们整体了解了下同构直出渲染方案在我们项目中的使用.正如我在上篇文章结尾所说的: 应用型技术的难点不是在克服技术问题,而是在于能够不断的结 ...

  2. React同构直出优化总结

    收录待用,修改转载已取得腾讯云授权 作者:郭林烁 joeyguo 原文地址 React 的实践从去年在 PC QQ家校群开始,由于 PC 上的网络及环境都相当好,所以在使用时可谓一帆风顺,偶尔遇到点小 ...

  3. 面向亿万级用户的QQ一般做什么?——兴趣部落的Web同构直出分享

    作者:李强,腾讯web开发工程师 商业转载请联系腾讯WeTest获得授权,非商业转载请注明出处. 原文链接:http://wetest.qq.com/lab/view/348.html 一.什么是同构 ...

  4. 面向亿万级用户的QQ一般做什么?——兴趣部落的 Web 同构直出分享

    欢迎大家前往腾讯云社区,获取更多腾讯海量技术实践干货哦~ 作者:李强,腾讯web开发工程师商业转载请联系腾讯WeTest获得授权,非商业转载请注明出处.原文链接:http://wetest.qq.co ...

  5. Vue(SPA) WebPack模块化打包、SEO优化(Vue SSR服务端同构直出)、全浏览器兼容完整解决方案

    白驹过隙,时光荏苒 大概去年这个时候写了angular 结合webpack的一套前端方案,今年此时祭出vue2结合webpack的一套前端方案. 明年的这个时候我又是在做什么... 读在最前面: 1. ...

  6. 腾讯新闻抢金达人活动node同构直出渲染方案的总结

    我们的业务在展开的过程中,前端渲染的模式主要经历了三个阶段:服务端渲染.前端渲染和目前的同构直出渲染方案. 服务端渲染的主要特点是前后端没有分离,前端写完页面样式和结构后,再将页面交给后端套数据,最后 ...

  7. React直出实现与原理

    前一篇文章我们介绍了虚拟DOM的实现与原理,这篇文章我们来讲讲React的直出. 比起MVVM,React比较容易实现直出,那么React的直出是如何实现,有什么值得我们学习的呢? 为什么MVVM不能 ...

  8. 打造高可靠与高性能的React同构解决方案

    前言 随着React的兴起, 结合Node直出的性能优势和React的组件化,React同构已然成为趋势之一.享受技术福利的同时,直面技术挑战,在复杂场景下,挑战10倍以上极致的性能优化. 什么是同构 ...

  9. React同构起步

    React同构从0到1 前言 如果你想快速做react同构的新项目建议你去了解next.js等成熟框架,本教程仅限于想了解如何从0开始实现一个同构环境过程的同学,对于想改造现有spa项目的同学也很有帮 ...

随机推荐

  1. Eclipse 3.5使用dropins的插件安装方式

    以前安装Eclipse插件有两种方式 1 直接copy插件到features/plugins目录 2 在links目录下创建链接文件. 而 Eclipse 3.5又推出另一种新的安装途径, 更加灵活. ...

  2. 第三章 深入 ZAB 协议

    上一节介绍了ZAB协议的内容,本节将从系统模型.问题描述.算法描述和运行分析四方面来深入了解 ZAB 协议. 系统模型 在一个由一组进程 n ={P1,P2,...Pn}组成的分布式系统中,每一个进程 ...

  3. sqlite中的replace、insert、update之前的区别

    本文转自http://www.ithao123.cn/content-933827.html,在此感谢作者 android数据库操作,有两种方式,一种用android提供给我们的数据库操作函数inse ...

  4. Linux下设置网卡随系统启动

    在GUI下安装RHEL,在配置网卡的时候,有时候会忘了勾选网卡随系统自动启动,解决方法是系统启动后,打开网卡配置文件/etc/sysconfig/network-script/ifcfg-eth*,将 ...

  5. 专题:mdadm Raid & LVM

    >FOR FREEDOM!< {A} Introduction Here's a short description of what is supported in the Linux R ...

  6. mysql基本命令(转)

    连接到本机上的MYSQL.首先打开DOS窗口,然后进入目录mysql\bin,再键入命令mysql -u root -p,回车后提示你输密码.注意用户名前可以有空格也可以没有空格,但是密码前必须没有空 ...

  7. 利用RBAC模型实现一个通用的权限管理系统

    本文主要描述一个通用的权限系统实现思路与过程.也是对此次制作权限管理模块的总结. 制作此系统的初衷是为了让这个权限系统得以“通用”.就是生产一个web系统通过调用这个权限系统(生成的dll文件), 就 ...

  8. Masonry 轻量级布局框架的使用

    iOS 提供了自动布局的方法,但是原生的方法使用太过麻烦 ,Masonry 框架提供了类似的方法,同样可以实现自动布局 ,代码更加直观,而且容易理解. Masonry 是一个轻量级的布局框架.拥有自己 ...

  9. PHP程序员的技术成长规划(转)

    第一阶段:基础阶段(基础PHP程序员) 重点:把LNMP搞熟练(核心是安装配置基本操作) 目标:能够完成基本的LNMP系统安装,简单配置维护:能够做基本的简单系统的PHP开发:能够在PHP中型系统中支 ...

  10. iOS push过去的时候界面不能完全退出

    iOS push过去的时候界面不能完全退出 解决方法:设置self.view.backgroundcolor 1. initWithFrame方法是什么?  initWithFrame方法用来初始化并 ...