当前位置: 首页 > news >正文

React之服务端渲染

一、是什么

在SSR中 (opens new window),我们了解到Server-Side Rendering ,简称SSR,意为服务端渲染

指由服务侧完成页面的 HTML 结构拼接的页面处理技术,发送到浏览器,然后为其绑定状态与事件,成为完全可交互页面的过程

其解决的问题主要有两个:

  • SEO,由于搜索引擎爬虫抓取工具可以直接查看完全渲染的页面
  • 加速首屏加载,解决首屏白屏问题

二、如何做

react中,实现SSR主要有两种形式:

  • 手动搭建一个 SSR 框架
  • 使用成熟的SSR 框架,如 Next.JS

这里主要以手动搭建一个SSR框架进行实现

首先通过express启动一个app.js文件,用于监听3000端口的请求,当请求根目录时,返回HTML,如下:

const express = require('express')
const app = express()
app.get('/', (req,res) => res.send(`
<html><head><title>ssr demo</title></head><body>Hello world</body>
</html>
`))app.listen(3000, () => console.log('Exampleapp listening on port 3000!'))

然后再服务器中编写react代码,在app.js中进行应引用

import React from 'react'const Home = () =>{return <div>home</div>}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(<Home/>)
app.get('/',(req,res) => res.send(`
<html><head><title>ssr demo</title></head><body>${content}</body>
</html>
`))app.listen(3001, () => console.log('Exampleapp listening on port 3001!'))

上面的过程中,已经能够成功将组件渲染到了页面上

但是像一些事件处理的方法,是无法在服务端完成,因此需要将组件代码在浏览器中再执行一遍,这种服务器端和客户端共用一套代码的方式就称之为同构

重构通俗讲就是一套React代码在服务器上运行一遍,到达浏览器又运行一遍:

  • 服务端渲染完成页面结构
  • 浏览器端渲染完成事件绑定

浏览器实现事件绑定的方式为让浏览器去拉取JS文件执行,让JS代码来控制,因此需要引入script标签

通过script标签为页面引入客户端执行的react代码,并通过expressstatic中间件为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(<Home/>)app.get('/',(req,res)=>res.send(`
<html><head><title>ssr demo</title></head><body>${content}<script src="/index.js"></script></body>
</html>
`))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 (<div><Route path="/" exact component={Home}></Route></div>
)

然后可以通过index.js引用路由信息,如下:

import React from 'react'
import ReactDom from 'react-dom'
import { BrowserRouter } from'react-router-dom'
import Router from'../Routers'const App= () => {return (<BrowserRouter>{Router}</BrowserRouter>)
}ReactDom.hydrate(<App/>, 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为必填参数,用于服务端渲染参数传递<StaticRouter location={req.path} context={{}}>{Router}</StaticRouter>))res.send(`<html><head><title>ssr demo</title></head><body><div id="root">${content}</div><script src="/index.js"></script></body></html>`)
})app.listen(3001, () => console.log('Exampleapp listening on port 3001!'))

这样也就完成了路由的服务端渲染

三、原理

整体react服务端渲染原理并不复杂,具体如下:

node server 接收客户端请求,得到当前的请求url 路径,然后在已有的路由表内查找到对应的组件,拿到需要请求的数据,将数据作为 propscontext或者store 形式传入组件

然后基于 react 内置的服务端渲染方法 renderToString()把组件渲染为 html字符串在把最终的 html进行输出前需要将数据注入到浏览器端

浏览器开始进行渲染和节点对比,然后执行完成组件内事件绑定和一些交互,浏览器重用了服务端输出的 html 节点,整个流程结束

相关文章:

React之服务端渲染

一、是什么 在SSR中 (opens new window)&#xff0c;我们了解到Server-Side Rendering &#xff0c;简称SSR&#xff0c;意为服务端渲染 指由服务侧完成页面的 HTML 结构拼接的页面处理技术&#xff0c;发送到浏览器&#xff0c;然后为其绑定状态与事件&#xff0c;成为完全可…...

jetson nano刷机更新Jetpack

只是记录个人在使用英伟达jetson Nano的经历,由于头一次尝试,所以特此记录需要的问题和经验。 一,英伟达刷机教程(jetson nano 版本) 本次我是直接刷机到TF卡,然后TF卡作为启动盘进行启动,我看网上有带EMMC版本的,好像可以直接把系统镜像安装到EMMC里面。但是有个问题…...

Android官方ShapeableImageView描边/圆形/圆角图,xml布局实现

Android官方ShapeableImageView描边/圆形/圆角图&#xff0c;xml布局实现 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"xmlns:app"http://schemas.android.…...

ubuntu扩大运行内存, 防止编译卡死

首先查看交换分区大小 grep SwapTotal /proc/meminfo 1、关闭交换空间 sudo swapoff -a 2、扩充交换空间大小&#xff0c;count64就是64G 1G x 64 sudo dd if/dev/zero of/swapfile bs1G count64 3、设置权限 sudo chmod 600 /swapfile 4、指定交换空间对应的设备文件 …...

Kafka集群修改单个Topic数据保存周期

在大数据部门经常使用Kafka集群&#xff0c;有的时候大数据部门可能在Kafka中的Topic数据保存时间不需要很长&#xff0c;一旦被消费后就不需要一直保留。默认Topic存储时间为7day&#xff0c;个别的Topic或者某台Kafka集群需要修改Topic数据保存的一个周期&#xff0c;调整为3…...

selenium模拟登录无反应

在使用自动化工具selenium时对某些网站登录界面send_keys输入账号密码&#xff0c;运行时却没有自己想要的结果出现&#xff0c;这是因为你碰到前端二般的开发人员&#xff0c;他们用的是HTML嵌套&#xff0c;这对后端人员造成了一些麻烦&#xff0c;废话不多说&#xff0c;直接…...

指针变量未分配空间或者初始化为空指针使用问题

提示&#xff1a;关于指针 文章目录 前言一、指针的使用总结 前言 在看c书籍的时候&#xff0c;看到浅复制和深复制时&#xff0c;说到成员为指针的时候&#xff0c;会出异常。但是其实没有更多的感想&#xff0c;但是联想到上次考试指针没分配空间导致程序异常的情况&#xf…...

力扣第763题 划分字母区间 c++ 哈希 + 双指针 + 小小贪心

题目 763. 划分字母区间 中等 相关标签 贪心 哈希表 双指针 字符串 给你一个字符串 s 。我们要把这个字符串划分为尽可能多的片段&#xff0c;同一字母最多出现在一个片段中。 注意&#xff0c;划分结果需要满足&#xff1a;将所有划分结果按顺序连接&#xff0c;得…...

js 代码中的 “use strict“; 是什么意思 ?

use strict 是一种 ECMAscript5 添加的&#xff08;严格&#xff09;运行模式&#xff0c;这种模式使得 Javascript 在更严格的条件下运行。 设立"严格模式"的目的&#xff0c;主要有以下几个&#xff1a; 消除 Javascript 语法的一些不合理、不严谨之处&#xff0c…...

用于读取验证码的 OCR 模型

介绍 此示例演示了使用功能 API 构建的简单 OCR 模型。除了结合 CNN 和 RNN 之外,它还说明了如何实例化新层并将其用作“端点层”来实现 CTC 损失。 设置 import os import numpy as np import matplotlib.pyplot as pltfrom pathlib import Path from collections import Co…...

Uniapp 跳转回上一页面并刷新页面数据

比如我从A页面跳转到B页面 然后再从B页面返回到A页面 顺带刷新一下A页面数据 let pages getCurrentPages(); // 当前页面 //获取当前页面栈let beforePage pages[pages.length - 3]; // //获取上一个页面实例对象beforePage.$vm.reloadList(); //调用它方法然后跳转…...

DeOldify 接口化改造 集成 Flask

类似的图片修复项目 GFPGAN 的改造见我另一篇文 https://blog.csdn.net/weixin_43074462/article/details/132497146 DeOldify 是一款开源软件&#xff0c;用于给黑白照片或视频上色&#xff0c;效果还不错。 安装部署教程请参考别的文章&#xff0c;本文基于你给项目跑通&…...

Vue 3响应式对象: ref和reactive

目录 什么是响应式对象&#xff1f; Ref Reactive Ref vs Reactive 适用场景&#xff1a; 访问方式&#xff1a; 引用传递&#xff1a; 性能开销&#xff1a; 响应式对象优点 响应式对象缺点 总结 Vue 3作为一种流行的JavaScript框架&#xff0c;提供了响应式编程的…...

Unity3D 如何用unity引擎然后用c#语言搭建自己的服务器

Unity3D是一款强大的游戏开发引擎&#xff0c;可以用于创建各种类型的游戏。在游戏开发过程中&#xff0c;经常需要与服务器进行通信来实现一些功能&#xff0c;比如保存和加载游戏数据、实现多人游戏等。本文将介绍如何使用Unity引擎和C#语言搭建自己的服务器&#xff0c;并给…...

带有 Vagrant 和 Virtualbox 的 Elasticsearch 集群

模拟分布式存储和计算环境的一种简单方法是使用 Virtualbox 作为 VM&#xff08;“虚拟机”&#xff09;的提供者&#xff0c;使用 Vagrant 作为前端脚本引擎来配置、启动和停止这些 VM。这篇文章的目标是构建一个集群虚拟设备&#xff0c;提供 Elasticsearch 作为可由主机使用…...

Cross Site Scripting (XSS)

攻击者会给网站发送可疑的脚本&#xff0c;可以获取浏览器保存的网站cookie&#xff0c; session tokens, 或者其他敏感的信息&#xff0c;甚至可以重写HTML页面的内容。 背景 XSS漏洞有不同类型&#xff0c;最开始发现的是存储型XSS和反射型XSS&#xff0c;2005&#xff0c;Am…...

VDA到Excel方案介绍之自定义邮件接收主题

VDA标准是德国汽车工业协会&#xff08;Verband der Automobilindustrie&#xff0c;简称VDA&#xff09;制定的一系列汽车行业标准。这些标准包括了汽车生产、质量管理、供应链管理、环境保护、安全性能等方面的规范和指南。VDA标准通常被德国和国际上的汽车制造商采用&#x…...

【opencv】【CPU】windows10下opencv4.8.0-cuda C++版本源码编译教程

【opencv】【CPU】windows10下opencv4.8.0-cuda C版本源码编译教程 提示:博主取舍了很多大佬的博文并亲测有效,分享笔记邀大家共同学习讨论 文章目录 【opencv】【CPU】windows10下opencv4.8.0-cuda C版本源码编译教程前言准备工具cmakeopencv4.8.0opencv_contrib CMake编译VS2…...

多分类loss学习记录

这里简单的记录在人脸识别/声纹识别中常用的分类loss。详细原理可以参考其他博客。 扩展资料1 扩展资料2 L-softmax A-softmax AM-softmax L-softmax &#xff1a;基于softmax加入了margin&#xff0c; Wx 改写为||w||||x||cos(角度)&#xff0c;将角度变为了m角度 A-softmax &…...

Linux创建逻辑卷并扩容(超详细)

目录 ​编辑 一、概念解析 1、LV逻辑卷 2、PV物理卷 3、VG卷组 二、扩容前准备 三、创建逻辑卷并扩容 1、打开虚拟机 2、进入root用户 3、查看新加入的硬盘 4、创建主分区 5、创建物理卷 6、打包为一个卷组 7、创建逻辑卷 8、格式化逻辑卷 9、挂载逻辑卷--开机自…...

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …...

CVPR 2025 MIMO: 支持视觉指代和像素grounding 的医学视觉语言模型

CVPR 2025 | MIMO&#xff1a;支持视觉指代和像素对齐的医学视觉语言模型 论文信息 标题&#xff1a;MIMO: A medical vision language model with visual referring multimodal input and pixel grounding multimodal output作者&#xff1a;Yanyuan Chen, Dexuan Xu, Yu Hu…...

Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)

文章目录 1.什么是Redis&#xff1f;2.为什么要使用redis作为mysql的缓存&#xff1f;3.什么是缓存雪崩、缓存穿透、缓存击穿&#xff1f;3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...

Leetcode 3577. Count the Number of Computer Unlocking Permutations

Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接&#xff1a;3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯&#xff0c;要想要能够将所有的电脑解锁&#x…...

全球首个30米分辨率湿地数据集(2000—2022)

数据简介 今天我们分享的数据是全球30米分辨率湿地数据集&#xff0c;包含8种湿地亚类&#xff0c;该数据以0.5X0.5的瓦片存储&#xff0c;我们整理了所有属于中国的瓦片名称与其对应省份&#xff0c;方便大家研究使用。 该数据集作为全球首个30米分辨率、覆盖2000–2022年时间…...

VTK如何让部分单位不可见

最近遇到一个需求&#xff0c;需要让一个vtkDataSet中的部分单元不可见&#xff0c;查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行&#xff0c;是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示&#xff0c;主要是最后一个参数&#xff0c;透明度…...

数据库分批入库

今天在工作中&#xff0c;遇到一个问题&#xff0c;就是分批查询的时候&#xff0c;由于批次过大导致出现了一些问题&#xff0c;一下是问题描述和解决方案&#xff1a; 示例&#xff1a; // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...

基于IDIG-GAN的小样本电机轴承故障诊断

目录 🔍 核心问题 一、IDIG-GAN模型原理 1. 整体架构 2. 核心创新点 (1) ​梯度归一化(Gradient Normalization)​​ (2) ​判别器梯度间隙正则化(Discriminator Gradient Gap Regularization)​​ (3) ​自注意力机制(Self-Attention)​​ 3. 完整损失函数 二…...

CRMEB 中 PHP 短信扩展开发:涵盖一号通、阿里云、腾讯云、创蓝

目前已有一号通短信、阿里云短信、腾讯云短信扩展 扩展入口文件 文件目录 crmeb\services\sms\Sms.php 默认驱动类型为&#xff1a;一号通 namespace crmeb\services\sms;use crmeb\basic\BaseManager; use crmeb\services\AccessTokenServeService; use crmeb\services\sms\…...

Linux nano命令的基本使用

参考资料 GNU nanoを使いこなすnano基础 目录 一. 简介二. 文件打开2.1 普通方式打开文件2.2 只读方式打开文件 三. 文件查看3.1 打开文件时&#xff0c;显示行号3.2 翻页查看 四. 文件编辑4.1 Ctrl K 复制 和 Ctrl U 粘贴4.2 Alt/Esc U 撤回 五. 文件保存与退出5.1 Ctrl …...