前几天,Next.js 15 正式发布了。然后我就马不停蹄的通过重构一个项目去感受 Next.js。
整体使用下来的感觉是,要用好 Next.js 的难度更高了。
这里最核心的两个原因,一方面是底层支持了 React 19,未来会成为主流的开发方式。另外一方面是 App Router 的重要性进一步被官方团队强调,经过一年多的持续预热和强推,Page Router 到 App Router 的升级已经成为了不可逆的趋势。
实际上在这个时间节点,React 19 还没有正式发布,他目前还只是 RC 版,但是,Next.js 的默认项目中,已经直接使用 React 19 RC 了。
React 19 的开发思维和之前的版本有很大的不同。其中最主要的影响,就是在底层代码中,完全的、彻底删除了模式。
从 React 17 开始,React 中就存在两种模式。
一种是传统的legacy模式。我们可以暂且简单粗暴的将其翻译为同步模式。因为该模式下的大多数关键底层函数,都是基于sync来命名。例如shceduleSyncCallback、performSyncWorkOnRoot等等。
另外一种就是Concurrent模式。也就是我们听到很多的并发模式。但是由于长期以来,对于并发模式的思考与支持并不成熟,因此在实际的开发中,有意识的使用并发模式来解决实际项目问题的团队并不算多。因此,并发模式更多的出现在技术类文章里,或者面试里。实际上要怎么用他,许多团队也还没有一个非常明确的方向与感受。
当然,经过长时间的预热与宣传,并发模式到目前为止,已经形成了共识,在 React 19 中,legacy模式的所有代码,都被直接删除。那么也就意味着,如果我们要用好 React 19,就必须要对并发模式有一个非常深刻的理解。
也正因为如此,许多项目要升级到 React 19 将会存在不少难度。当然,由于并发模式实际上已经过渡了很多年,许多团队的项目本身就是直接基于 React 18 来开发,那么升级的难度会小很多。
除此之外,React 19 所提倡的开发模式,与之前的版本相比,也出现了很大的区别。
一种很重要的思路就是:我们需要尽可能的把 useEffect 变成一个非常小众的 hook,只会偶尔使用一下。
这会让许多 React 开发者感受到不适应。因此,在我的付费小册《React 19 全解》中,我花了很大的篇幅来介绍 React 19 的细节,帮助大家能够快速掌握这种新的开发思维。
App Router 实际上也已经经历了一两年时间的预热,但是通过群友的反馈来看,依然会有很多同学在使用他的过程中感觉不适应。
在 Next.js 15 中,App Router 变成了官方团队主推的方案。这里最核心的是要 重推 React Server Component【简称:RSC】
这就不是一个简单的升级了,而是一次完全的变革。
开发者需要非常明确的区分客户端组件与服务端组件。如果用得不好,你可能会发现你的项目里到处都是use client,这样不仅不能享受到 Next.js 给你带来的提升,反而会感觉处处受到限制。
关于这个点,许多人会对use client的使用感到困惑的原因是因为,没有理解到use client他代表的含义是:边界,而不仅仅是标识当前组件是一个客户端组件。
这里的边界指的是,服务端与客户端组件的边界。我们只需要标识边界,那么边界之下的所有组件,都会自动变成客户端组件,而不需要我们手动在每个组件中添加use client。
当然,这里的上下级关系,指的并不是父子结点,而是文件引入的结构。
这带来的一个强度很大的影响就是:对于使用者的组件合理拆分有很高的要求。这会让许多的基础使用者感觉到不适应。许多初中级开发者很难做到合理的拆分组件。
因此,他们会吐槽说,Next.js 的组件拆得太碎了,过度拆分等等。但是有的时候这种拆分是必须的,如果我们能够合理的把服务端逻辑与客户端逻辑处理好,对于项目的整体运行性能是非常有帮助的。这是 Next.js 追求的一个很重要的指标。
对组件的属性问题分析不明确的话,经常会在开发中遇到报错。因为服务端组件有非常多的 api 是不能使用的。如果你在编写这个组件的过程中,并没有思考该组件到底是 server 组件,还是 client 组件,你大概率会遇到很多报错
当我们使用浏览器才存在的一些行为,例如点击事件时,我们就必须使用 client 组件。这要求我们在开发阶段,就要做好动静分离,把点击事件相关的逻辑单独拆分出去重新封装一个客户端组件
这可能是很多人难受的一个比较重要点。因为在 App Router 中,有几个重要的 API 消失了。他们就是
这些 API 的消失,会让初学者很难清晰的判断出来 SSG 与 SSR 的界限在哪里。例如,当我们想要提前获取到页面所需要的数据时,就使用getStaticProps,这样,页面呈现所需要的数据,就可以在构建的时候获得
这几个 API 存在的好处就是,页面到底是 SSG 还是 SSR,是由开发者来控制的。
但是在 App Router 中,逻辑大变。
开发者不再需要去区分我到底需要渲染成什么 SSG 还是 SSR。
如果我们要切换到动态渲染内容,那么可能需要通过调整缓存策略来实现。如下图所示
这造成的结果是,可能我们写的代码大多数都会被渲染成 SSG,而当我们需要一些动态生成的页面【SSR】,就进一步要求我们对每个动态 API 有深刻的理解。
学习成本变得更高了。
但是我个人更喜欢这样的方式。因为在实际的开发中,我们发现,如果项目中存在大量动态渲染的内容,当访问量规模变大之后,服务端的压力会变得非常大,从而让访问速度变得更慢。因此,尽可能少的使用 SSR 是我在项目开发中的一个比较大的原则。
我会尽量把与具体用户强关联的展示信息放到客户端组件中去处理。这里的前提是,经过分析发现,与客户强关联的内容大多数情况下都没必要做 SEO。
Next.js 15 发布之后,对三方生态库来说,是一个巨大的挑战。因为许多库对 RSC 的支持并不是那么友好。因此在升级之前,大家一定要做好调研工作。评估好具体的风险与影响。
当然,新版本在开发体验上的提升是非常明显的,无论是构建速度,还是编译速度,又或者是项目性能,都有非常明显的提升。如果三方库的影响是可控的,那么升级到新版本所带来的收益非常大。