那么什么是同构?如何实现同构应用呢?
下面请听我慢慢叨叨。我叨叨的同时也会引出问题,希望大家能在看的同时也一起思考起来。
我们上一节说过,传统的ssr
和目前流行的csr
方案spa
都不够完美,所以我们需要能综合这两者优点的技术 - react ssr (SPA+SSR)
。
每次刷新页面的时候数据是从服务端直出,然后后续的访问就是 spa
的体验,即能解决SEO
问题,也能保持页面切换的效率,服务器的压力要比传统的ssr
也相对小。
我们现在既然已经知道了该技术的作用和意义,那么接下来就该分析下它的原理了。
为什么react
能够实现 SPA+SSR
这种体验呢 ?
虚拟 dom
使用react ssr
技术开发出的最终产物其实就是SPA+SSR
的结合。
其中的SSR
指的是在服务端渲染组件。
而组件可以在服务端渲染的根本原因就是虚拟 DOM
。
平时我们都习惯使用jsx
来编写react
的组件。但jsx
只是一个抽象的语法糖,看上去是写组件,其实我们写的是对象,只是这样写更方便,更符合我们前端开发者的编写习惯,看上去就像写html
,多爽。
虚拟 DOM
除了在渲染时用于提高渲染性能,以最小的代价来更新视图的作用外,另一个作用就是为组件的跨平台渲染提供可能。
虚拟DOM
本身 就是一个内存中的对象,通过对象的属性来描述要渲染的具体是什么元素以及内容。
举个栗子
下面是我们一个组件的render
部分
- 1
- 2
- 3
上面的结构可以转换为下面的对象表示(虚拟 dom)
const tree = {
tag:‘ul’, // 节点标签名
props: { // DOM的属性,用一个对象存储键值对
id: ‘list’
},
children: [ // 该节点的子节点
{tag: ‘li’, props: {class: ‘item’}, children: [‘1’]},
{tag: ‘li’, props: {class: ‘item’}, children: [‘2’]},
{tag: ‘li’, props: {class: ‘item’}, children: [‘3’]},
]
}
从上面我们可以看出这就是个普通对象。
既然有了这样的对象,我们就可以轻松的把这个对象转换我们想要的表现形式,比如
html
格式,而这个html
就是我们要直出的内容。不过这个转换的过程不需要我们来完成,
react
已经帮我们完成,其本身就已提供了内置方法来支持服务端渲染。同构
–
React
虚拟DOM
为我们实现SSR
提供了基础条件,但是单纯的SSR
和 传统的SSR
没有什么区别,React
中的 组件也只能用作其他模板语言的代替品。。。那么为什么还要基于
React
来实现SSR
呢?既然这种技术能够出现,肯定是因为有他独特的魅力和优点。
我们要明白一点,服务端渲染的核心作用。
SSR
主要是直接表达出页面最基础和核心的内容这就够了。剩下的工作就要交给浏览器了,浏览器端需要对页面的交互完成进一步的渲染、事件绑定等增强功能。
说到这里好像有点明白了,意思不就是服务端把首屏的内容直出,让用户更快的看到页面,然后后面的数据采用
js
来异步请求和加载。貌似不用react
一样可以做到的呀。诶,好像说的没啥毛病。确实方案不只一种,但是我们基于
react
来实现可以更高效,写更少的代码。因为我们可以构造同构应用。所谓同构,就是指前后端公用一套代码,比如我们的组件可以在服务端渲染也可以在客户端渲染,但都是同一个组件。这样的方式应该是可以甩传统方式好几条街了把。
当然打造同构应用还有另外一个得天独厚的条件,双端使用同一种语言 - javascript。
SSR
部分我们使用node
就能完成,所以我们才可以编写同一套代码供双端执行。另外还有一个重要的特性也是同构的重要体现,浏览器接管页面后的进一步渲染(交互、事件)过程中,会判断已有的
DOM
结构和浏览器渲染出的结构是否相同,若相同,则不重复渲染,只需要绑定事件即可。当然上面的这个特性是
react
提供的双端节点对比功能,也是为了最大限度的提高页面的渲染效率,尽可能的重用服务端给出的html
结构。打造同构应用
说了这么多其实本质还是
react
的能力,有了它的支持才能玩的转,这当然也得力于node
。说到这里,可能有同学会这样认为,既然
react
都为我们提供了,那我们实现起来就很方便了呀。和我们做SPA
应用的时候差不多吧,只写一套代码,然后在服务端调用下react
服务端渲染的相关api
,浏览器端也不需要管,react
也帮我们搞定了。说的好像没啥毛病,但是打造同构应该不是仅仅调用几个
api
的事儿,如果你只是打算写一个demo
玩玩,我觉得是可以的。同构的最大优点是双端可以公用一套代码,但它是一把双刃剑,因为他还涉及到服务端,所以复杂性大大增加。
另外双端也不是完全能公用一套代码,还需要做很多差异化的处理。不只是代码层面的,还会涉及到架构和工程化。
虽然我们已经了解了
react ssr
的最核心的原理,但是并不能保证你能迅速的开发出这样体验的应用。所以我们需要一个轮子,这个轮子本身已经帮我们完备了双端的差异处理,开发者只需要关心自身业务逻辑,开发中无差异化。
而这个轮子就是我们接下来要一步一步实现的
React SSR
应用开发骨架。双端对比机制
上面也提到了这个概念,这里需要详细的说明一下。
为了实现服务端渲染,打造同构应用,
React
内部实现了相关的API
,可以让我们方便的将一个组件转换为html
字符串。下面介绍几个
API
import ReactDOMServer from’react-dom/server’
ReactDOMServer
类可以帮我们在服务端渲染组件 - 得到组件的html
字符串。下面是介绍该模块的两个方法
- renderToString()
ReactDOMServer.renderToString(element)
把一个
React
组件渲染为原始的HTML
。我们可以用这个方法在服务端生成
HTML
字符串,然后将该字符串返回给浏览器端,完成页面内容的初始化,同时让搜索引擎可以抓取你的页面来达到优化SEO
的目的。另外在
react 16
前该方法生成的html
内容的每一个DOM
节点都有一个data-react-id
属性,根节点会有一个data-react-checksum
属性。组件在服务端渲染后,在浏览器端还会渲染一次,来完成组件的交互等逻辑。渲染时,
react
在浏览器端会计算出组件的data-react-checksum
属性值,如果发现和服务端计算的值一致,则不会进行客户端渲染。所以data-react-checksum
属性的作用是为了完成组件的双端对比。如果两个组件的
props
和DOM
结构是相同的,那么计算出的该属性值就是一致的。也可以换个角度来理解,当双端渲染的组件的
props
和DOM
结构一致时,那么该组件只会渲染一次,客户端会采用服务端渲染的结果,仅作事件绑定等处理,这会让我们的应用有一个非常高效的初次加载体验。ps:
data-react-checksum
属性值是通过Adler-32
校验算法实现的。有兴趣的可以了解下此算法,这里就不详细说明了。- renderToStaticMarkup()
ReactDOMServer.renderToStaticMarkup(element)
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
外链图片转存中…(img-DU2h0J0n-1714814815638)]既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!