脚本宝典收集整理的这篇文章主要介绍了

React 服务器端渲染和客户端渲染效果对比

脚本宝典小编觉得挺不错的,现在分享给大家,也给大家做个参考,希望能帮助你少写一行代码,多一份安全和惬意。
<p><code></p> <p>最近在学习 <a href="http://www.js-code.com/tag/react" title="React" target="_blank">React</a> 的服务端渲染,于是使用 Express+<a href="http://www.js-code.com/tag/react" title="React" target="_blank">React</a> 写了一个 Demo,用于对比和客户端渲染的差异。<a href="https://github.com/yhlben/react-ssr-demo" rel="nofollow noreferrer" target="_blank">github 地址</a></p> <p>先看一下效果吧:</p> <p>1、访问 <a href="https://yinhengli.com:8084/" rel="nofollow noreferrer" target="_blank">服务器端渲染 Online Demo</a></p> <p>2、我们可以看到,首屏数据很快的就显示出来了,可是页面的进度条却还在加载中(因为客户端 js 很大)。</p> <p>3、当进度条加载完成后,页面才能进行交互操作(切换路由,登录等)。</p> <p>4、查看网页源代码,页面内容都在页面中。</p> <blockquote><p>效果不明显的话,可以打开控制台,在 Network 栏 Disable cache,然后刷新。</p></blockquote> <p>通过这次简单的访问,我们就能看出服务器端渲染的 2 大特点,<code>首屏直出</code>,<code>SEO 友好</code>。</p> <h2 id="articleHeader0">为什么要做服务器端渲染?</h2> <p>1、访问 <a href="https://yinhengli.com:8086/" rel="nofollow noreferrer" target="_blank">客户端渲染 Online Demo</a></p> <p>2、我们可以看到,首屏至少等待了 6 秒才渲染出来,这对于一般的用户,是难以容忍的。</p> <p>3、不过一旦渲染完成,页面就立即可交互了(切换路由,登录等)。</p> <p>4、查看网页源代码,页面只有一个空 <a href="http://www.js-code.com/tag/div" title="div" target="_blank">div</a> 容器,而没有实际内容。</p> <p>通过这次访问,我们就能看出客户端渲染的特点,<code>首屏加载时间长</code>,<code>SEO 不友好</code>,但<code>可见即可操作</code>。</p> <p>其实我们在访问客户端渲染的页面时,请求到的只是一个 html 空壳,里面引入了一个 js 文件,所有的内容都是通过 js 进行插入的,类似于这样:</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="<!DOCTYPE html><br /> <html lang=&quot;en&quot;><br /> <head><br /> <meta charset=&quot;UTF-8&quot; /><br /> <meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /><br /> <meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;ie=edge&quot; /><br /> <title>ssr</title><br /> </head><br /> <body></p> <div id=&quot;root&quot;></div> <p> <script src=&quot;bundle.js&quot;></script><br /> </body><br /> </html>" title="" data-original-title="复制"></span> </div> </p></div> <pre class="xml hljs"><code class="html"><span class="hljs-meta">&lt;!DOCTYPE html&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span> /&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span> /&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">http-equiv</span>=<span class="hljs-string">"X-UA-Compatible"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"ie=edge"</span> /&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>ssr<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name"><a href="http://www.js-code.com/tag/div" title="浏览关于“div”的文章" target="_blank" class="tag_link">div</a></span> <span class="hljs-attr">id</span>=<span class="hljs-string">"root"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"bundle.js"</span>&gt;</span><span class="undefined"></span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span></code></pre> <p>正是因为页面是由 js 渲染出来的,所以会带来如下几个问题:</p> <p>1、页面要等待 js 加载,并执行完成了才能展示,<code>在这期间页面展现的是白屏</code>。</p> <p>2、爬虫不能识别 js 内容,所以抓取不到任何数据,<code>不利于 SEO 优化</code>。</p> <p>为了解决这 2 个问题,我们可以使用服务器端渲染。</p> <h2 id="articleHeader1"><a href="http://www.js-code.com/tag/react" title="浏览关于“React”的文章" target="_blank" class="tag_link">React</a> 服务器端渲染流程</h2> <p>之前说道,客户端渲染的页面,请求到的是一个 html 空壳,然后通过 js 去渲染页面。那如果请求到的直接是一个渲染好的页面,是不是就可以解决这 2 个问题了呢?</p> <p>没错,服务器端渲染就是这个原理。</p> <h3 id="articleHeader2">简化流程</h3> <p>1、服务器端使用 renderToString 直接渲染出包含页面信息的<code>静态 html</code>。</p> <p>2、客户端根据渲染出的静态 html 进行<code>二次渲染</code>,做一些绑定事件等操作。</p> <blockquote><p>服务器端没有 <a href="http://www.js-code.com/tag/dom" title="DOM" target="_blank">DOM</a>,Window 等概念,所以只能渲染出字符串,不能进行事件绑定,样式渲染等。</p> <p>只有第一次访问页面时才使用服务器端渲染,之后会被客户端渲染接管。</p> </blockquote> <h2 id="articleHeader3">开始写代码吧</h2> <p>接下来我们一起来写一个 React 服务器端渲染 Demo。</p> <h3 id="articleHeader4">编写路由</h3> <p>这里使用 react-router 对前后端代码进行同构。</p> <p>1、客户端</p> <p>使用 react-router-dom 下的 <code>BrowserRouter</code> 进行前端路由控制。</p> <p>2、服务器端</p> <p>使用 react-router-dom 下的 <code>StaticRouter</code> 进行静态路由控制,具体操作如下:</p> <ul> <li>使用 react-router-config 下的 matchRoutes 匹配后端路由,使用 renderRoutes 渲染匹配到的路由。</li> <li>使用 react-router-dom/server 下的 renderToString 方法,渲染出 html 字符串,并返回给前端。</li> </ul> <blockquote><p>使用 StaticRouter 中通过 context 可以和前端页面通信,传参。</p></blockquote> <h3 id="articleHeader5">状态管理</h3> <p>在 React 中,我们常常使用 redux 来存储数据,管理状态。</p> <p>1、客户端</p> <p>使用 redux 进行状态管理,使用 react-redux 提供的 Provider 为组件注入 store。</p> <p>2、服务器端</p> <p>和客户端一样,但每一次接收到请求需产生一个新的 store,避免多个用户操作同一个 store。</p> <h3 id="articleHeader6">数据请求</h3> <p>1、客户端</p> <p>使用 ax<a href="http://www.js-code.com/tag/ios" title="ios" target="_blank">ios</a> 在 componentDidMount 中请求数据。</p> <p>2、服务器端</p> <p>同样使用 ax<a href="http://www.js-code.com/tag/ios" title="浏览关于“ios”的文章" target="_blank" class="tag_link">ios</a> 去请求数据,但是服务器端不会触发 componentDidMount 生命周期。我们可以在后端匹配到路由的时候,进行数据请求,并把数据存入 redux 中的 store,然后渲染出包含数据的 html 页面,为了避免客户端二次请求,服务器端向 window 中注入 REDUX_STORE 数据,客户端直接使用此数据作为客户端 redux 的初始数据,以免发生数据抖动。</p> <p>具体操作如下:</p> <ul> <li>在 routes 对象上挂载一个自定义方法 loadData。</li> <li>在服务器端 matchRoutes 后,如果有 loadData,则进行请求数据,并把请求到的数据写入 store 中。</li> <li>服务器端等待请求完成后,再进行 renderToString 渲染。</li> </ul> <h3 id="articleHeader7">样式处理</h3> <p>1、客户端</p> <p>使用 css-loader,style-loader 打包编写好的 css 代码并插入到页面中。</p> <p>2、服务器端</p> <p>由于 style-loader 会插入到页面,而服务器端并没有 document 等概念,所以这里使用 isomorphic-style-loader 打包 css 代码。</p> <ul> <li>引入 isomorphic-style-loader 后,客户端就可以通过 styles._getCss 方法获取到 css 代码。</li> <li>通过 staticRouter 中的 context 把 css 代码传入到后端。</li> <li>后端拼接好 css 代码,然后插入到 html 中,最后返回给前端。</li> </ul> <h3 id="articleHeader8">SEO 优化</h3> <p>SEO 主要是针对搜索引擎进行优化,为了提高网站在搜索引擎中的自然排名,但搜索引擎只能爬取落地页内容(查看源代码时能够看到的内容),而不能爬取 js 内容,我们可以在服务器端做优化。</p> <p>常规的 SEO 主要是优化:<code>文字</code>,<code>链接</code>,<code>多媒体</code></p> <ul> <li>内部链接尽量保持相关性</li> <li>外部链接尽可能多</li> <li>多媒体尽量丰富</li> </ul> <p>由于网页上的文字,链接,图片等信息都是产品设计好的,技术层面不能实现优化。我们需要做的就是优化页面的 title,description 等,让爬虫爬到页面后能够展示的更加友好。</p> <p>这里借助于 react-helmet 库,在服务期端进行 title,meta 等信息注入。</p> <h2 id="articleHeader9">你可能不需要服务器端渲染?</h2> <p>现在,我们成功地通过服务器端渲染解决了<code>首次加载白屏时间</code>和 <code>SEO 优化</code>。但也带来了一些问题:</p> <ul> <li>服务器端压力增大。</li> <li>引入了 <a href="http://www.js-code.com/tag/node" title="node" target="_blank">node</a> 中间层,可维护性增大。</li> </ul> <p>以上两个问题归根结底还是钱的问题。服务器压力大,可以通过买更多的服务器来解决。可维护性增大,可以招募更多人来维护。但是对于小型团队来说,增加服务器,招募更多维护人员,都会额外增加的支出,所以在选择服务器端渲染时,要权衡好利弊。</p> <h3 id="articleHeader10">解决 SEO 的另一种方法</h3> <p>如果只是想优化 SEO,不妨使用预渲染来实现,推荐使用 prerender 库来实现。</p> <p>prerender 库的原理:<code>先请求客户端渲染的页面,把客户端渲染完成之后的结果,拿给爬虫看</code>,这样爬虫获取到的页面就是已经渲染好的页面。prerender 库在使用时会开启一个服务,通过传递 url 来解析客户端渲染页面,这就需要我们对服务器端架构进行调整。</p> <blockquote> <p>1、 nginx 判断访问类型</p> <blockquote><p>2.1、 用户访问 :直接走客户端渲染</p> <p>2.2、 爬虫访问 :走预渲染</p> </blockquote> </blockquote> <h2 id="articleHeader11">总结</h2> <p>通过这个 Demo,让我加深了对服务器端的理解,如有错误,麻烦多多指正,谢谢大家!</p> <p>如果觉得有用得话给个 &#x2b50; 吧。<a href="https://github.com/yhlben/react-ssr-demo" rel="nofollow noreferrer" target="_blank">react-ssr-demo</a></p> <p></code></p>

总结

以上是脚本宝典为你收集整理的

React 服务器端渲染和客户端渲染效果对比

全部内容,希望文章能够帮你解决

React 服务器端渲染和客户端渲染效果对比

所遇到的程序开发问题,欢迎加入QQ群277859234一起讨论学习。如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典网站推荐给程序员好友。 本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。

80%的人都看过