理解了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 数据库映射库

我能想到的,最大的成功就是无愧于自己的心。