app 目录
在过往的 nextjs 版本中,pages目录内的文件会被自动处理成路由。next 13 在继续保有 pages 目录的基础上新增了一个 app 目录。
page(路由对应的页面)
layout
在多个页面之间共享 UI。在导航时,布局会保留状态、保持交互并且不会重新呈现。在 next 12 中,每次进入路由,页面都会重新渲染一遍 UI,想要实现像 spa 单页面应用的体验是件比较麻烦的事情,得益于 layout,nextjs 从此可以很轻松的实现持久化缓存。
在 app 目录内通过建立多个 layout 可以实现嵌套布局。
template
该路由下的公共模版,与 layout 跨路由保持状态不同,template 在切换路由时会刷新。
Turbopack
Next.js 13 使用 Turbopack,它是 Webpack 新继任者,由 Webpack 的创建者 Tobias Koppers 和 Next.js 团队使用 Rust 编写。
Turbo 可以缓存任何函数的结果,当程序再次运行时,函数不会重新运行,除非它们的输入发生变化。Turbo的这种增量记忆系统使得其具拥有快到飞起的 HMR 速度。Turbopack 仍处于 alpha 阶段,目前Turbopack 还不能配置。
服务端组件 vs 客户端组件
目前 nextjs 13 所有组件均默认为服务端组件,如果需要使用客户端组件在最顶部增加 “use client” 标识。
在服务端组件可直接使用 async/await 来进行异步数据的获取。
nextjs 不提倡在客户端组件上向服务端获取数据,如果这是必须的,我们可以整体作为服务端组件的方式,把客户端组件拆出来,作为组件引入,在服务端组件进行异步的处理。另外,React 最近对 Promises RFC 的支持引入了一种强大的新方法来获取数据和处理组件内部的 promises,通过了增加一个 hook use 的提议。
// 服务端组件
async function getData() {
const res = await fetch('https://api.example.com/...')
return res
}
export default async function Page() {
const name = await getData()
// 传递到客户端组件的props,会被序列化,所以不能传递 function
return <ClientCompoent data={name} />
}
-----------------------------强势分割---------------------------
// 客户端组件
'use client';
async function fetchNote() {
const res = await fetch('https://api.example.com/...')
return res
}
export default function ClientCompoent(props) {
const { data } = props
const note = use(fetchNote(id))
const [number, setNumber] = useState(0)
return (
<div onClick={()=>setNumber(number+1)}>{number}-{note}</div>
)
}
何时使用服务端组件与客户端组件?
服务端组件的优势是什么?
- 可以使用nodejs的各种能力
- 利于seo,首屏速度快,大幅减少FCP
- 客户端 JavaScript 打包体积大大减少
服务端组件和 ssr 有什么区别?
- ssr 在首屏渲染之后,后续的更新仍然是在客户端进行
- 服务端组件则完全在服务端完成渲染,渲染之后再发送到客户端
Streaming and Suspense
SSR 通过尽快向用户显示非交互式内容来帮助提高页面的感知加载性能。但是,它可能会很慢,因为在所有数据获取完成之前,整个页面都被阻止呈现。此时可使用 app 目录内的 loading.js (用户所有路由) 或者 Suspense (用于更精细的控制)处理,不必等待整个页面加载完毕就可以开始交互。
// app/dashboard/loading.tsx
export default function Loading() {
return <p>Loading...</p>
}
// app/dashboard/page.tsx
import { Suspense } from "react";
import { PostFeed } from "./Components";
export default function Posts() {
return (
<section>
<Suspense fallback={<p>Loading feed...</p>}>
<PostFeed />
</Suspense>
</section>
);
}
其它
- 兼容最新 React 18版本
- 改进next/image。
- 改进next/link:自动内置 a 标签,不需要在标签里面手动加 a 标签了。
- 官方文档