理解了React,我要对Next.js下手了。
学一个技术栈,按照我的习惯,肯定是要写一个项目,这次写什么呢?
哼哼哼,这次要做一个真正有用的东西!我已经事先做好了调研,开好了支付接口,这次要做一个搞钱的项目!!
很久以前我刚看到Next.js时,我觉得它和Webpack一样,是个打包器。
后来发现,这东西可以拿来在服务器渲染页面。
现在我发现,这是一个让我感觉相当炸裂的东西。
早就幻想过,如果后端和前端都用js写,那得省多少代码啊,Next.js何止都用js,前后端都是在一个项目里面的。ψ(`∇´)ψ
到建项目的那一刻我才知道,Next.js是基于React的。React赛高
下面是我觉得Next.js牛的地方。
Next Action
这是一个相当炸裂的东西。
众所周知,Next.js把前端和后端写在同一个项目中(似乎也可以做纯前端,但是我这次做的全栈),但是即便这样,也是有前后端之分的,一些代码是跑在服务器上的,一些代码是跑在浏览器上的。
但是,跑在浏览器上的代码可以直接调用跑在服务器上的函数
当然,因为网络本身是异步的,所以这个函数必须是异步的。
这个功能是相当炸裂,写SpringBoot瞬间就不香了。
而且这个函数还可以是闭包函数,闭包上下文保存在浏览器上。
流式传输
Suspense这个东西,跑在客户端上,当它的组件抛出promise的时候它就会展示显示后备方案(loading)
跑在服务器上呢?
一开始我以为服务器上大概不允许使用吧。
但是实际上,服务器上的React组件都是异步函数,这些组件简单套在Suspense就能实现流式传输,Next.js会把先执行完的Suspense发到浏览器。
所以,Next.js并不是简单的执行页面渲染函数然后等待完全渲染完成,编码,发送。而是正在渲染的时候就已经开始了。
很牛的功能呢,怎么实现的呢?会不会产生额外请求对服务器产生负面影响呢?
小实验
首先我写了这样子的代码:
export default async function Page() {
return (
<>
{
[0,0,0,0,0,0,0,0,0,0].map((_,idx)=>{
return <TimerSuspense key={idx} />
})
}
</>
)
}
async function TimerSuspense() {
return<Suspense fallback={<div>Loading...</div>}>
<Timer />
</Suspense>
}
async function Timer(){
await new Promise(resolve => setTimeout(resolve, Math.random() * 5000));
return <div>OK</div>
}然后刷新页面,观察网络请求。
实际上只进行了一个http请求,这个请求首先把能发的东西(静态的,一堆Loading)先全都发过来了:
<!--$?--><template id="B:0"></template>
<div>Loading...</div>
<!--/$--><!--$?--><template id="B:1"></template>
<div>Loading...</div>
<!--/$--><!--$?--><template id="B:2"></template>
<div>Loading...</div>
<!--/$--><!--$?--><template id="B:3"></template>
<div>Loading...</div>
<!--/$--><!--$?--><template id="B:4"></template>
<div>Loading...</div>
<!--/$--><!--$?--><template id="B:5"></template>
<div>Loading...</div>
<!--/$--><!--$?--><template id="B:6"></template>
<div>Loading...</div>
<!--/$--><!--$?--><template id="B:7"></template>
<div>Loading...</div>
<!--/$--><!--$?--><template id="B:8"></template>
<div>Loading...</div>
<!--/$--><!--$?--><template id="B:9"></template>
<div>Loading...</div>
<!--/$-->但是发完之后响应没有结束,body标签和html标签都没闭合
然后后面就开始慢慢发这些东西:
<script>
self.__next_f.push([1, '19:["$","div",null,{"children":"OK"}]\n']);
</script>
<div hidden id="S:1"><div>OK</div></div>
<script>
$RC("B:1", "S:1");
</script>(前面还发了一段script定义了$RC函数)
所以,不会因为产生额外请求而对服务器产生负面影响。
但是增加了复杂度,对服务器和浏览器都有负面影响,但这微不足道
Ajax导航
从一个页面跳转到另一个页面的时候,需要去加载另一个页面,页面有一段时间空白。
很久之前我就发现,很多网站在跳转的时候能很平滑地过渡过去,似乎是用Js实现的。
调研发现,这个效果可以用Pjax实现,本来打算这次项目就试试的。
但这个功能Next.js自带了,而且默认是开着的。
而且Next还有个预取功能,当页面出现一个链接的时候,为了提高加载速度,条件合适就会去提前加载目标页面。
缓存
和React一样,能懒则懒,只要状态没变,就不重新渲染。
甚至把fetch都魔改了,很多时候fetch变不变是不确定的,看到fetch就不能懒了,必须重新渲染,但是魔改过的fetch有一套缓存机制,Next.js能知道什么时候fetch可能会变。
除此之外还有一系列的缓存机制,性能感觉应该挺好的。
技术选型和规范
选择一套生产级的库和使用一定的规范,今后React全栈开发就它了。
Next.js APP路由
Sass Module 模块化的sass
TypeScript
antd UI组件库
zod 数据校验库
Sequelize 数据库映射库