前言
前面给大家探讨过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 = () => {
}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 = () => (
Home
About
)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 的特性,它允许你在组件内部写一些样式,你只需要在组件内使用
标签来写 css 即可。举个例子,比如我们在 pages/index.js 里添加样式:
import Layout from '../components/MyLayout.js'import Link from 'next/link'function getPosts () { return [ { id: 'hello-nextjs', title: 'Hello Next.js' }, { id: 'learn-nextjs', title: 'Learn Next.js is awesome' }, { id: 'deploy-nextjs', title: 'Deploy apps with ZEIT' } ]}export default () => (
My Blog
{getPosts().map((post) => ( href={`/post?title=${post.title}`}> {post.title} ))}
h1, a {
font-family: "Arial";
}
ul {
padding: 0;
}
li {
list-style: none;
margin: 5px 0;
}
a {
text-decoration: none;
color: blue;
}
a:hover {
opacity: 0.6;
}
`} )
在上述代码中,我们没有直接使用
标签来书写样式代码,而是写在一个模板字符串({``})
里面。Next.js 使用 babel插件来解析 styled-jsx ,它支持样式命名空间,未来还将支持变量赋值。
需要注意的是:styled-jsx 的样式不会应用到子组件,如果想要该样式适用于子组件,可以在 styled-jsx 标签添加属性global:
。
结尾:
好了,到这里基本就把next的搭建,基本使用,路由等介绍完了,已经解决的基本使用,洗完能帮助到你,毕竟服务端渲染在日常中还是很常见,比如一些C端产品经常需要做服务端渲染,最典型的就是一些电商网站,所以服务端渲染这块的知识还是建议大家掌握的哈!
- END -
结伴同行前端路