CSR: 客户端渲染(Client-side Rendering)
渲染工作主要交由客户端去完成。
这也是在一般情况下我们使用React的方式。浏览器从服务端接收html和javascript文件, 并通过javascript发送请求,获取数据,使用数据完成渲染工作。
客户端渲染存在一定的缺点 :
由于渲染依赖于服务端javascript的下载处理以及请求数据的返回,在此之前页面内容并不会显示完全。 这也同时导致了SEO问题。
Next.js默认进行提前渲染 ,页面HTML是在服务端提前生成的, 当页面被使用时,服务端会直接返回处理好的HTML静态页面。
在Next.js中使用客户端渲染:
- 不使用服务端渲染的api:如getServerSideProps;
- 渲染使用的数据使用useEffect() 配合axios 或者fetch 等去获取;
js
import React, { useState, useEffect } from 'react'
export default function Page() {
const [data, setData] = useState(null)
useEffect(() => {
const fetchData = async () => {
const res = await fetch('https://...')
setData(res)
}
}, [])
return <div>{data}</div>
}
SSR:服务端渲染(Server-side Rendering)
渲染工作主要在服务端进行。
通过服务端去发出数据请求,数据返回后在服务端去处理成一个完整的页面, 处理完成之后直接给客户端返回HTML。 这种方式会带来更好的首屏加载速度,有利于优化SEO, 并且由于客户端并不能直接去获取页面数据,提高了安全性。 当然由于在服务端完成的工作增加,服务端压力会提升, 并且由于浏览器需要等待服务端处理页面,服务端的响应时间可能会相应的增加。
在Next.js中使用服务端渲染:
1.在组件文件中暴露一个async函数getServerSideProps;
2.在getServerSideProps中请求数据并将返回的数据通过props传递给Page组件;
js
export default function Page({ data }) {
// 渲染数据...
}
export async function getServerSideProps() {
// 从外部 API 获取数据
const res = await fetch('https://...')
const data = await res.json()
// 使用props给组件传递数据
return { props: { data } }
}
SSG:静态站点生成(Static Site Generation)
当页面内容不是动态生成,或者需要实时交互情况下,比如一个纯展示页面,而不是聊天页面。 此时直接在构建打包阶段,就直接将页面处理为静态的HTML文件;
在Next.js中使用静态站点生成:
1.页面是静态的不依赖其他数据: 打包时直接生成静态文件不需要额外处理
js
function About() {
return <div>About</div>
}
export default About
2.页面内容需要用到请求的数据,比如获取文章内容:
使用getStaticProps
:
- 在组件文件中暴露一个async函数
getStaticProps
,该函数会在打包构建时被调用,请求数据 getStaticProps
获取的数据通过props
传递给Page
组件
js
export default function Blog({ posts }) {
}
export async function getStaticProps() {
const res = await fetch('https://.../posts')
const posts = await res.json()
// By returning { props: { posts } }, the Blog component
return {
props: {
posts,
},
}
}
3.页面路径需要用到请求的数据,在Next.js中存在动态路由,比如文章页面:article/[id]/...
,id
并不是固定的Nextjs中需要使用getStaticPaths
去定义预渲染的路径。
js
// 这个函数在 build 时会调用
export async function getStaticPaths() {
// 请求 API 获取数据
const res = await fetch('https://.../posts')
const posts = await res.json()
// 基于 posts 获取我们想要预渲染的路径
const paths = posts.map((post) => ({
params: { id: post.id },
}))
// 在 build 时我们只会预渲染 paths 数组中的路径
return { paths, fallback: false }
}
在暴露getStaticProps
的基础上再暴露一个getStaticPaths
函数。函数会在构建打包时被调用,path
包含了需要预渲染的路径, 而fallback
则决定了当访问到的是没有被预渲染包含的路径时需要如何处理:
false
:按404处理;tru
:在第一次请求的过程中使用SSR获取对应的数据并返回并缓存html;blocking
: 和true同样的处理方式,不过true时进入页面和getStaticProps
是同时进行的,相当于异步而,blocking
则是等到getStaticProps返回数据后再进入页面。
ISR:静态增量生成(Incremental Static Regeneration)
在某些情况下,页面的大部分内容在打开之后是不会变化的,但是少部分内容需要动态更新 。 在使用SSG的情况下,再通过重新构建更新内容是不现实的。 ISR可以只生成部分需要更新的页面。 在第一次构建时所有页面的静态页面会被生成,当内容更新时,ISR会在服务端重新生成新页面并缓存,并在下一次请求过程中替换旧页面。
在Nextjs中使用静态增量生成:
只需在SSG配置的基础上:getStaticProps
中配置revalidate
,单位为秒,为页面更新间隔。
js
function Blog({ posts }) {
return (
<ul>
{posts.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
)
}
export async function getStaticProps() {
const res = await fetch('https://.../posts')
const posts = await res.json()
return {
props: {
posts,
},
revalidate: 10,
}
}
export async function getStaticPaths() {
const res = await fetch('https://.../posts')
const posts = await res.json()
const paths = posts.map((post) => ({
params: { id: post.id },
}))
return { paths, fallback: 'blocking' }
}
export default Blog
当revalidate
被设为10时,在10s之内访问页面都会显示旧的HTML页面,当10s时间后发生了一次请求,旧页面仍旧会被使用,但是此时Next.jss会开始重新处理生成新的HTML页面,并在下次请求后返回新的HTML页面。
在Next.js中这些渲染方式可以组合使用,从而实现更好的用户体验。