服务端渲染理解
服务端渲染时;
输入一个菜单路由路径,
在没有ssr时,全部是 react 配合 router 实现的渲染,
这应该有一个逻辑,就是,每次跳转到新的页面,跳转时,
react router 渲染好想要的内容,渲染完毕调用类似:
history.pushState(‘data to be passed’, ‘Title of the page’, ‘/test111999’);
来修改浏览器的url,此时url是变化了,但不会触发浏览器类似重新加载刷新的效果,自然就不会从后端请求接口。
当使用ssr模式时,
react router,当发生跳转页面时,router 就改变了策略,
会向后端发起请求,获取服务端页面,
又由于 服务端页面里面 加了 客户端的js spa 代码引用,
当服务端页面内容渲染完毕后,
js 的spa 开始执行, react router 此时会根据 浏览器的url,
走spa 的渲染,会找到路由对应的组件页面,然后生成 虚拟dom,
此虚拟dom,为了比较页面,服务端渲染的页面是通过 reactStaticRouter 生成的,
一定包含了 虚拟dom 和改虚拟dom的id 标识,
那么此时,客户端 spa 渲染时,生成了自己的 虚拟dom对象,之前浏览器从服务端不光拿到了页面还拿到了虚拟dom信息,
那么此时 客户端 spa 会对比自己的 虚拟dom对象,与 页面已经渲染好的来自服务端的虚拟dom对象,
如果发现是同一个,
客户端就不再执行 真实的dom 的删除创建,而直接进行dom的事件挂载,
至此,整个页面渲染完毕。
而页面的后续交互都只与客户端 spa 渲染有关,与服务端渲染没有关系,
直至页面发生跳转,上面的过程将重新来一遍。
服务端ssr+spa的理解关键在于:
服务端ssr的代码里面是会通过src加载spa的代码的。
页面url发生变化与是否要发起请求是独立的两个事情,
比如 history.pushState(‘data to be passed’, ‘Title of the page’, ‘/test111999’);
时,页面url发生变化,但不会发起任何请求,
只有两种方式,才会发请求,要么手动刷新页面,要么再调用 page.reload 才会刷新页面。
另外一个就是 先渲染服务端返回的页面内容,跟着客户端的spa也开始渲染内容,
由于服务端与客户端都是通过 react 编译出来的 虚拟dom,因此可以进行比较后,挂载事件。
第三个是 react 提供了服务端和客户端同构能力,一套代码可以运用在两端,主要体现又提供了一套路由生成对应的html的API 如 reactStaticRouter;
网页源代码 是怎么被修改的
关于这个疑问,参考 微信群。
目前已经确定,虽然 node 根据路由定义了 多个接口用于返回 html,
但只要用到的是服务端渲染,只有第一次是从服务端请求回 html 进行页面渲染,之后的交互 都是客户端自己实现,与服务端再无关系。
虽然之后每次改变路由时,网页的源代码,也会随之改变,但这已经与服务端再无关系,
之所以源代码会改变,我觉得大概率是 ReactDom.hydrate 有关,
而且 由于 客户端的react 具有双端对比能力,因此客户端的react 也能生成 跟服务端渲染的renderToString 一样的html 字符串,
然后用这个字符串 来修改网页源代码。
两个假定
- 假定 react 有能力在页面不刷新的情况下,修改网页源代码。
- 假定 服务端渲染,只有第一次刷新页面时,从后端接口请求到html,用于页面渲染,后期无论页面如何跳转交互,都是客户端spa的行为,与服务端渲染并无关系。
其实这个好理解,当第一次刷新页面后,spa接管页面,以后的逻辑就跟spa一样了,页面发生跳转,虽然看起来浏览器url发生了变化,其实是假性变化,并不会请求后端,
从这一点看,后期确实再没有请求后端接口的可能,因此也就没有了再跟服务端发生联系的可能。
所谓的服务端渲染
服务端渲染有一定的误导性,应该说是服务端组装好html、以及样式等等 得到的一个html 字符串。
参考5 「小试牛刀」- 初步认识同构 - 交互实现
当然还有一个重点就是浏览器端的组件渲染和服务端渲染的差别,服务端只是生成-html 字符串,也只会执行组件的componentWillMount方法。