本文转载自微信公众号「JS每日一题」,作者灰灰。转载本文请联系JS每日一题公众号。

在龙凤等地区,都构建了全面的区域性战略布局,加强发展的系统性、市场前瞻性、产品创新能力,以专注、极致的服务理念,为客户提供成都做网站、成都网站制作、成都外贸网站建设 网站设计制作按需策划,公司网站建设,企业网站建设,成都品牌网站建设,成都全网营销推广,成都外贸网站建设公司,龙凤网站建设费用合理。
在SSR中,我们了解到Server-Side Rendering ,简称SSR,意为服务端渲染
指由服务侧完成页面的 HTML 结构拼接的页面处理技术,发送到浏览器,然后为其绑定状态与事件,成为完全可交互页面的过程
其解决的问题主要有两个:
在react中,实现SSR主要有两种形式:
这里主要以手动搭建一个SSR框架进行实现
首先通过express启动一个app.js文件,用于监听3000端口的请求,当请求根目录时,返回HTML,如下:
- const express = require('express')
 - const app = express()
 - app.get('/', (req,res) => res.send(`
 SSR demo - Hello world
 - `))
 - app.listen(3000, () => console.log('Exampleapp listening on port 3000!'))
 
然后再服务器中编写react代码,在app.js中进行应引用
- import React from 'react'
 - const Home = () =>{
 - return
 home- }
 - export default Home
 
为了让服务器能够识别JSX,这里需要使用webpakc对项目进行打包转换,创建一个配置文件webpack.server.js并进行相关配置,如下:
- const path = require('path') //node的path模块
 - const nodeExternals = require('webpack-node-externals')
 - module.exports = {
 - target:'node',
 - mode:'development', //开发模式
 - entry:'./app.js', //入口
 - output: { //打包出口
 - filename:'bundle.js', //打包后的文件名
 - path:path.resolve(__dirname,'build') //存放到根目录的build文件夹
 - },
 - externals: [nodeExternals()], //保持node中require的引用方式
 - module: {
 - rules: [{ //打包规则
 - test: /\.js?$/, //对所有js文件进行打包
 - loader:'babel-loader', //使用babel-loader进行打包
 - exclude: /node_modules/,//不打包node_modules中的js文件
 - options: {
 - presets: ['react','stage-0',['env', {
 - //loader时额外的打包规则,对react,JSX,ES6进行转换
 - targets: {
 - browsers: ['last 2versions'] //对主流浏览器最近两个版本进行兼容
 - }
 - }]]
 - }
 - }]
 - }
 - }
 
接着借助react-dom提供了服务端渲染的 renderToString方法,负责把React组件解析成html
- import express from 'express'
 - import React from 'react'//引入React以支持JSX的语法
 - import { renderToString } from 'react-dom/server'//引入renderToString方法
 - import Home from'./src/containers/Home'
 - const app= express()
 - const content = renderToString(
 ) - app.get('/',(req,res) => res.send(`
 SSR demo - ${content}
 - `))
 - app.listen(3001, () => console.log('Exampleapp listening on port 3001!'))
 
上面的过程中,已经能够成功将组件渲染到了页面上
但是像一些事件处理的方法,是无法在服务端完成,因此需要将组件代码在浏览器中再执行一遍,这种服务器端和客户端共用一套代码的方式就称之为「同构」
重构通俗讲就是一套React代码在服务器上运行一遍,到达浏览器又运行一遍:
浏览器实现事件绑定的方式为让浏览器去拉取JS文件执行,让JS代码来控制,因此需要引入script标签
通过script标签为页面引入客户端执行的react代码,并通过express的static中间件为js文件配置路由,修改如下:
- import express from 'express'
 - import React from 'react'//引入React以支持JSX的语法
 - import { renderToString } from'react-dom/server'//引入renderToString方法
 - import Home from './src/containers/Home'
 - const app = express()
 - app.use(express.static('public'));
 - //使用express提供的static中间件,中间件会将所有静态文件的路由指向public文件夹
 - const content = renderToString(
 ) - app.get('/',(req,res)=>res.send(`
 SSR demo - ${content}
 - `))
 - app.listen(3001, () =>console.log('Example app listening on port 3001!'))
 
然后再客户端执行以下react代码,新建webpack.client.js作为客户端React代码的webpack配置文件如下:
- const path = require('path') //node的path模块
 - module.exports = {
 - mode:'development', //开发模式
 - entry:'./src/client/index.js', //入口
 - output: { //打包出口
 - filename:'index.js', //打包后的文件名
 - path:path.resolve(__dirname,'public') //存放到根目录的build文件夹
 - },
 - module: {
 - rules: [{ //打包规则
 - test: /\.js?$/, //对所有js文件进行打包
 - loader:'babel-loader', //使用babel-loader进行打包
 - exclude: /node_modules/, //不打包node_modules中的js文件
 - options: {
 - presets: ['react','stage-0',['env', {
 - //loader时额外的打包规则,这里对react,JSX进行转换
 - targets: {
 - browsers: ['last 2versions'] //对主流浏览器最近两个版本进行兼容
 - }
 - }]]
 - }
 - }]
 - }
 - }
 
这种方法就能够简单实现首页的react服务端渲染,过程对应如下图:
在做完初始渲染的时候,一个应用会存在路由的情况,配置信息如下:
- import React from 'react' //引入React以支持JSX
 - import { Route } from 'react-router-dom' //引入路由
 - import Home from './containers/Home' //引入Home组件
 - export default (
 - )
 
然后可以通过index.js引用路由信息,如下:
- import React from 'react'
 - import ReactDom from 'react-dom'
 - import { BrowserRouter } from'react-router-dom'
 - import Router from'../Routers'
 - const App= () => {
 - return (
 - {Router}
 - )
 - }
 - ReactDom.hydrate(
 , document.getElementById('root')) 
这时候控制台会存在报错信息,原因在于每个Route组件外面包裹着一层div,但服务端返回的代码中并没有这个div
解决方法只需要将路由信息在服务端执行一遍,使用使用StaticRouter来替代BrowserRouter,通过context进行参数传递
- import express from 'express'
 - import React from 'react'//引入React以支持JSX的语法
 - import { renderToString } from 'react-dom/server'//引入renderToString方法
 - import { StaticRouter } from 'react-router-dom'
 - import Router from '../Routers'
 - const app = express()
 - app.use(express.static('public'));
 - //使用express提供的static中间件,中间件会将所有静态文件的路由指向public文件夹
 - app.get('/',(req,res)=>{
 - const content = renderToString((
 - //传入当前path
 - //context为必填参数,用于服务端渲染参数传递
 - {Router}
 - ))
 - res.send(`
 SSR demo  ${content}- `)
 - })
 - app.listen(3001, () => console.log('Exampleapp listening on port 3001!'))
 
这样也就完成了路由的服务端渲染
整体react服务端渲染原理并不复杂,具体如下:
node server 接收客户端请求,得到当前的请求url 路径,然后在已有的路由表内查找到对应的组件,拿到需要请求的数据,将数据作为 props、context或者store 形式传入组件
然后基于 react 内置的服务端渲染方法 renderToString()把组件渲染为 html字符串在把最终的 html进行输出前需要将数据注入到浏览器端
浏览器开始进行渲染和节点对比,然后执行完成组件内事件绑定和一些交互,浏览器重用了服务端输出的 html 节点,整个流程结束
参考文献
                当前题目:面试官:说说React服务端渲染怎么做?原理是什么?
                
                本文URL:http://www.csdahua.cn/qtweb/news45/144245.html
            
网站建设、网络推广公司-快上网,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 快上网