Next.js作为React技术栈的一员,在选择使用Next.js时,SEO以及加载速度快往往是选择Next.js的一个主要原因,至少对于Yasol我自己来说是这样的,从React切换到Next.js的时候会明显觉得Next.js有各种限制,各种规范,感觉没有React那么的自由那么的灵活。
犹如那种突然从自由职业转到了按时到点上班的那种感觉,浑身难受,但是用久了之后,就会慢慢发现Next.js其实确实是一款很强大的框架,不单单是SEO以及单方面的加载速度快,还为项目中考虑到了很多容易忽略的安全性问题,反正对于目前的我来说,确实是对Next.js越来越兴趣了
回归主题,在使用Next.js中一般都难免会使用SSG或者SSR,特别是一些有SEO需求的官网或者博客,目前yasol是项目中使用了Next.js且自己重构的Vue博客也是使用的Next.js,重构也是因为SEO问题且目前从事React方向,所以选择了Next.js。
就拿博客案例来说,这里每一篇博文的前面会携带用户id,因此结构如下图所示,在pages/[uid]/[did].tsx
这个时候,我们是使用SSG的时候就会使用到两个方法,getStaticPaths和getStaticProps
其中getStaticPaths用于获取SSG渲染的所有文章路径,可以只提供部分,后续新的自动增量
而getStaticProps则会通过上面的所有路径去匹配当前的路径,然后用匹配到的uid和did去请求服务器拿到当前博客的文章
export const getStaticPaths = async () => {
const res = await axios.get("https://ssgdemo.usemock.com/paths");
// console.log(res.data.data);
const list = res.data.data;
const paths = list.map((item: { uid: any; did: any; }) => ({
params: {
uid: item.uid,
did: item.did
},
}))
console.log(paths);
return {
paths,
// fallback: true //设置为true,部署后不会增量更新
fallback: "blocking" //搭配revaildate可以实现ISR动态增量
// fallback: false //当前路由不存在在全部路由路径中,则直接返回404
}
}
这里使用ISR,设置了页面缓存过期时间为60s,可以自己设置时间
export const getStaticProps = async ({ params }: { params: { uid: string, did: string } }) => {
console.log(params);
const res = await axios.get(`https://ssgdemo.usemock.com/${params.uid}/${params.did}`);
console.log(res.data.data.time);
return {
props: {
time: res.data.data.time
},
revalidate: 60
}
}
至此,页面SSG静态渲染已经完成,基本达到了我们的需求,并且博文的页面会缓存60s,在这60s中,刷新或者其他用户访问,都会直接返回缓存,而不请求数据库的数据。
但是如果说我们的在60s之内修改了博文的内容,但是因为还在60s内,所以我们的更新并不会马上现在出来,这个时候我们就可以使用api的方式,让页面的缓存直接过期,这样下次访问的时候就会从新去请求新的数据
设置API
1.在.env环境变量中新增一个变量
*注意
如果环境变量名字里面有NEXT_PUBLIC则表示当前环境变量可以在服务端读取到,也可以在客户端读取到
# update ssg revalidate
NEXT_PUBLIC_UPDATE_SSG="YASOLUPDATE"
2.在pages/api文件夹下新建revalidate.ts
这里可以自己改写,yasol为了方便,在调用这个api的时候也传递了path,到时候直接根据传递的path进行更新缓存即可
export default async function handler(req, res) {
console.log(req.query);
// Check for secret to confirm this is a valid request
//这里的process.env.NEXT_PUBLIC_UPDATE_SSG名字要与你设置在项目中的环境变量名字相同
if (req.query.secret !== process.env.NEXT_PUBLIC_UPDATE_SSG) {
return res.status(401).json({message: "Invalid token"});
}
try {
// this should be the actual path not a rewritten path
// e.g. for "/blog/[slug]" this should be "/blog/post-1"
await res.revalidate(req.query.path);
return res.json({revalidated: true});
} catch (err) {
// If there was an error, Next.js will continue
// to show the last successfully generated page
return res.status(500).send("Error revalidating");
}
}
3、调用
例如在博客后台管理系统中,我们可以在调用修改接口成功,再调用当前项目的api
项目地址——>https://www.360yahoo.cn
则调动更新缓存的接口地址为——>https://www.360yahoo.cn/api/revalidate?secret=${环境变量设置的值}&path=${需要更新的路径}
调用成功后接口会返回一下信息,则表示缓存已经失效,下次访问会请求新的数据
下面是我写的演示地址
SSG页面:nextjs-ssg-demo-rho.vercel.app/1/1
访问上面的地址后,会看到一个时间,缓存时间为60秒,在60秒呢,时间会一直停留在缓存的那个时间
清除缓存:nextjs-ssg-demo-rho.vercel.app/api/revalid…
当调用上面的清除缓存后,再次访问则会请求新的时间
github地址:github.com/izz520/next…
文章写的不是很好,如果觉得写的乱可以看看github的源码,会比较清晰
当然有任何问题欢迎大家指出来,共同学习