React之服务端渲染

入坑互联网

共 5741字,需浏览 12分钟

 ·

2021-12-19 15:25

前言

前面给大家探讨过vue的服务端渲染,今天就通过本文带领大家一起认识关于react的服务端渲染知识。

开始之前先带领大家回顾一下什么是服务端渲染,为什么要服务端渲染这些问题!

什么是服务器端渲染

服务器端渲染简称 SSR(server side render),就是在服务器端将数据和 HTML 融合后返回给浏览器

使用 React 构建客户端应用程序,默认情况下,可以在浏览器中输出 React 组件,进行生成 DOM 和操作 DOM。React 也可以在服务端通过 Node.js 转换成 HTML,直接在浏览器端“呈现”处理好的 HTML 字符串,这个过程可以被认为 “同构”,因为应用程序的大部分代码都可以在服务器和客户端上运行。

为什么使用服务器端渲染

与传统 SPA(Single Page Application - 单页应用程序)相比,服务器端渲染(SSR)的优势主要在于:

1.vue,angular,react等都为spa应用框架,按照常规的渲染,数据是异步渲染的,这样的话不利于搜索引擎爬虫抓取,不信你看看页面源码里是否有数据渲染。

2.更好的用户体验,对于缓慢的网络情况或运行缓慢的设备,加载完资源浏览器直接呈现,无需等待所有的 JavaScript 都完成下载并执行,才显示服务器渲染的HTML。

服务端渲染的弊端

1.由于服务端与浏览器客户端环境区别,选择一些开源库需要注意,部分库是无法在服务端执行,比如你有 document、window 等对象获取操作,都会在服务端就会报错,所以在选择的开源库要做甄别。

2.使用服务端渲染,比如要起一个专门在服务端渲染的服务,与之前,只管客户端所需静态资源不同,你还需要 Node.js 服务端的和运维部署的知识,对你所需要掌握的知识点要求更多 服务器需要更多的负载,在 Node.js 中完成渲染,由于 Node.js 的原因大量的CPU资源会被占用。

服务端渲染和客户端渲染的区别

客户端渲染路线:

1.请求html

2.服务端返回html

3.浏览器下载html里面的js/css文件

4.等待js文件下载完成

5.等待js加载并初始化完成

6.js代码可以运行后由js代码向后端请求数据( ajax/fetch )

7.等待后端数据返回

8.react-dom( 客户端 )从无到完整地,把数据渲染为响应页面

服务端渲染路线:

1.请求html

2.服务端请求数据

3.服务器初始渲染(服务端性能好,较快)

4.服务端返回已经有正确内容的页面

5.客户端请求js/css文件

6.等待js文件下载完成

7.等待js加载并初始化完成

8.react-dom( 客户端 )把剩下一部分渲染完成( 内容小,渲染快 )

React服务端渲染之Next.js

本文主要讲的是针对react进行服务端渲染的next.js,它跟vue的nuxt.js一样,可以不需要大量改造现有的项目代码,从而实现服务端渲染,本文就带领大家一起来认识它吧!

Next.js 是一个轻量级的 React 服务端渲染应用框架。

next.js的特性:

1.以文件系统为基础的客户端路由(File-System Routing)

2.代码自动分隔使页面加载更快(Automatic Code Splitting)

3.默认服务端渲染模式(Server Side Rendering)

4.开发环境支持模块热替换(Hot Module Replacement)

5.支持JSX和ES6语法

6.支持typescript

7.可以运行在Express和其他Node.js的HTTP 服务器上

8.可以定制化专属的babel和webpack配置

开始构建一个Next.js项目?

在命令行工具中依次执行下面语句:

// 在本地创建一个项目跟目录$ mkdir hello-next 
// 切换到项目根目录$ cd hello-next
// 用npm初始化项目$ npm init -y
// 将react和next安装到本地依赖$ npm install --save react react-dom next
// 创建文件夹 pages$ mkdir pages

创建完文件夹之后,打开hello-next文件下的package.json文件,在 scripts 下添加一个script,如下:

{  "scripts": {    "dev": "next"  }}

项目准备工作完成,运行下面这条命令开启项目服务器:

$ npm run dev

创建第一个页面

在 pages 目录下创建一个名称为 index.js 的文件, 内容如下:

const Index = () => { 

Hell Next.js

}export default Index

现在, 再次访问 http://localhost:3000, 在页面上你会看到 “Hello Next.js”. 这里, 我们只是从 pages/index.js 模块导出了一个简单的 React 组件. 同理, 可以编写你自己的模块并且导出它.

next路由

所有的页面的路由都是通过后端服务器来控制的,要想实现客户端路由,需要借助Next.js的Link API。

我们在项目根目录下创建components文件夹,并在该目录下创建Header和Layout组件公共组件,Header组件用于页面导航头部,Layout组件用于页面布局,具体代码如下如下:

// Header.jsimport Link from 'next/link'
const linkStyle = { marginRight: 15}
const Header = () => ( )
export default Header
// Layout.jsimport Header from './Header'
const layoutStyle = { margin: 20, padding: 20, border: '1px solid #DDD'}
const Layout = (props) => (
{props.children}
)
export default Layout

接下来再修改pages目下的about.js、post.js和index.js文件,把刚刚编写的公共组件用于页面布局,修改以后的具体代码如下:

// about.jsimport Layout from '../components/Layout'
export default () => (

This is the about page

)
// post.jsimport Layout from '../components/Layout'
export default (props) => (

{props.url.query.title}

This is the blog post content.

)
// index.jsimport Layout from '../components/Layout'import Link from 'next/link'
const PostLink = (props) => (
  • {props.title}
  • )
    export default () => (

    My Blog

    注:可以使用 使链接和预加载在后台同时进行,来达到页面的最佳性能。

    路由遮盖(Route Masking)

    Next.js上提供了一个独特的特性:路由遮盖(Route Masking)。它可以使得在浏览器上显示的是路由A,而App内部真正的路由是B。这个特性可以让我们来设置一些比较简洁的路由显示在页面,而系统背后是使用一个带参数的路由。

    比如上面的例子中,地址栏中显示的是 http://localhost:3000/post?title=Hello%20Next.js ,这个地址含有一个title参数,看着很不整洁。

    我们就可以用Next.js来改造路由,使用路由遮盖来创建一个更加简洁的路由地址。比如我们可以看到在post.js使用了as属性,该属性的作用是进行路由覆盖,在不使用该属性时,在点击链接后浏览器地址栏显示的是http://localhost:3000/post?title=Hello%20Next.js,而使用了as属性就将该地址改造成 http://localhost:3000/p/hello-nextjs

    请求接口,获取数据

    Next.js 在 React 的基础上为组件添加了一个新的特性:getInitialProps (有点像是getInitialState),它用于获取并处理组件的属性,返回组件的默认属性。我们可以在该方法中请求数据,获取页面需要的数据并渲染返回给前端页面。

    $ npm install --save isomorphic-unfetch

    修改 pages/index.js 里的内容,换成下面这样:

    import Layout from '../components/MyLayout.js'import Link from 'next/link'import fetch from 'isomorphic-unfetch'
    const Index = (props) => (

    Batman TV Shows

      {props.shows.map(({show}) => (
    • href={`/post?id=${show.id}`}> {show.name}
    • ))}
    )
    Index.getInitialProps = async function() { const res = await fetch('https://api.tvmaze.com/search/shows?q=batman') const data = await res.json()
    console.log(`Show data fetched. Count: ${data.length}`)
    return { shows: data }}
    export default Index

    上述代码中,在 getInitialProps 中使用了 async 和 await 来处理异步请求,并将取到的数据当做一个属性赋给页面,页面拿到这个属性的值后会用于页面的初始化渲染。

    样式化组件

    Next.js 提供了一个 css-in-js 的特性,它允许你在组件内部写一些样式,你只需要在组件内使用 )

    在上述代码中,我们没有直接使用