ReactSSR-DEMO-移动端适配

ssr介绍

服务端渲染,将网页内容在服务器端生成发送到浏览器技术。(csr为客户端渲染)

应用场景

  1. 搜索引擎优化(SEO)-提升网站在搜索引擎中的排名
  2. 首屏加载速度-ssr可以在服务器端生成HTML页面 3.隐藏某些数据-csr需要从服务器将数据下载进行动态渲染,ssr由于数据在服务端实现可以隐藏部分数据

实现

流程:服务端渲染组件为 string,拼接成 html 返回,浏览器渲染出返回的 html,然后执行 hydrate,把渲染和已有的 html 标签关联。 很早之前服务端就是通过 JSP、PHP 等模版引擎,渲染填充数据的模版,产生 html 返回的。只不过这时候没有组件的概念. 同样的组件在服务端渲染了一次,在客户端渲染了一次,这种可以在双端渲染的方式,叫做同构渲染。 服务端导入渲染组件,调用react-dom/server中的renderToString的方法将组件的渲染内容输出为字符串返回客户端

服务端组件和App组件

import express from "express";
import React from "react";
import { renderToString } from "react-dom/server";

import App from "../ui/App";

const app = express();

app.get("/chat", (_: unknown, res: express.Response) => {
  console.log("res", res);
  console.log("res.send", res.send(renderToString(<App />)));
  res.send(renderToString(<App />));
});

app.listen(4000, () => {
  console.log("Listening on port 4000");
});

使用npm run start:1 开启服务

import React, { useCallback } from "react";

export default ({ userName = "unknown" }: { userName?: string }) => {
  const log = useCallback(() => {
    console.log("Nice world");
  }, []);

  return (
    <div>
      <p>react ssr demo</p>
      <p>{userName}</p>
      <button onClick={log}> 点击 </button>
    </div>
  );
};



server 端就会使用 renderToString 将 <App /> 渲染成 html 字符串,然后通过 send 返回给前端

<div>
<p>react ssr demo</p>
<p>unknown</p>
<button> 点击 </button>
</div>

hydrate 复活组件

浏览器接收到 html 就会把它渲染出来,这时候已经有标签了,只需要把它和组件关联之后,就可以更新和绑定事件了。 到此拿到了一个 html 并没有任何的 js,事件绑定等无法实现的,要复活组件的交互需要很重要的一步 - hydrate 也就是常说的水合。 hydrate 即通过 react 将对应的组件重新渲染到 SSR 渲染的静态内容上,类似于 render 差异点在于 render 会忽略 root 元素中现有的 dom 而 hydrate 则会复用并会进行内容匹配检查。 hydrate 会在渲染的过程中,不创建 html 标签,而是直接关联已有的。这样就避免了没必要的渲染 客户端代码:

import React from 'react';
import { hydrateRoot } from 'react-dom/client';

import App from './App';

hydrateRoot(document.getElementById('root')!, <App {...window.__initialState} />);


打包完成后生成一个 bundle.js 即可在客户端使用它来进行 hydrate。 修改服务端代码:

import express from "express";
import { renderToString } from "react-dom/server";
import React from "react";

import App from "../ui/App";

const app = express();

app.get("/", (_: unknown, res: express.Response) => {
  res.send(
    `
<div id="root">${renderToString(<App />)}</div>
<script src="/bundle.js"></script>
`
  );
});

app.use(express.static("static"));

app.listen(4000, () => {
  console.log("Listening on port 4000");
});


在静态内容的外层套上 root 元素,然后在下方引入我们刚刚编译的脚本,然后就可以在客户端看到我们想要的结果

image.png

image.png

服务端是怎么 render 出字符串的,浏览器端又是怎么 hydrate 的呢?

服务端渲染就是拼接 html 的过程,组件和元素分别有不同的渲染逻辑:组件的话就传入参数执行,元素的话就拼接字符串。

响应式适配

//设置页面的字体大小
var init = function () {
  var clientWidth = document.documentElement.clientWidth || document.body.clientWidth;
  if (clientWidth >= 640) {
    clientWidth = 640;
  }
  var fontSize = 20 / 375 * clientWidth;
  document.documentElement.style.fontSize = fontSize + "px";
}

init();

window.addEventListener("resize", init);

该函数用于设置页面的字体大小。它首先获取当前浏览器窗口的宽度,使用document.documentElement.clientWidth获取文档根元素<html>元素的宽度,如果该值不存在,则使用document.body.clientWidth获取body元素的可视宽度的宽度。 通过判断获取到的宽度是否大于等于640像素,如果是,则将其值设为640,以限制最大宽度。接下来,根据计算公式 20 / 375 * clientWidth,计算出需要设置的字体大小(以像素为单位)。 通过document.documentElement.style.fontSize将字体大小应用到文档根元素上。 通过window.addEventListener("resize", init)添加了一个事件监听器,当浏览器窗口的大小发生改变时,会触发init函数,从而重新计算并设置字体大小以实现响应式布局效果

代码执行了一次init()函数,用于初始化页面的字体大小。

知识点

  • useState接受一个初始值,它返回一个数组,里面包含两个值,第一个是拿来使用的值(state),第二个是用来更新这个值的函数(setState)

  • 使用setState更新数据时,在它后面使用state还是未更新的值

  • 如果想要setState依赖上一个setState的值,可以写一个函数,函数接收上一个state,并返回要设置的state,类似于setState(prevState => newState)

  • setState会将原本的值与传过来的值进行浅比较,如果前后两个值对比相等,则不进行渲染操作,直接return,所以对于Object类型的值在setState时需要进行一个浅拷贝操作。

全部评论

相关推荐

拒绝无效加班的小师弟很中意你:求职意向没有,年龄、课程冗余信息可以删掉,需要提升项目经历。排版需要修改。
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务