Next.js 13 新特性

2,309 阅读3分钟

app 目录

在过往的 nextjs 版本中,pages目录内的文件会被自动处理成路由。next 13 在继续保有 pages 目录的基础上新增了一个 app 目录。

1.webp

page(路由对应的页面)

page.webp

layout

在多个页面之间共享 UI。在导航时,布局会保留状态、保持交互并且不会重新呈现。在 next 12 中,每次进入路由,页面都会重新渲染一遍 UI,想要实现像 spa 单页面应用的体验是件比较麻烦的事情,得益于 layout,nextjs 从此可以很轻松的实现持久化缓存。

22.webp

在 app 目录内通过建立多个 layout 可以实现嵌套布局。

template

该路由下的公共模版,与 layout 跨路由保持状态不同,template 在切换路由时会刷新。

Turbopack

Next.js 13 使用 Turbopack,它是 Webpack 新继任者,由 Webpack 的创建者 Tobias Koppers 和 Next.js 团队使用 Rust 编写。

Turbo 可以缓存任何函数的结果,当程序再次运行时,函数不会重新运行,除非它们的输入发生变化。Turbo的这种增量记忆系统使得其具拥有快到飞起的 HMR 速度。Turbopack 仍处于 alpha 阶段,目前Turbopack 还不能配置。

image

服务端组件 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>
    )
}
  

何时使用服务端组件与客户端组件?

截屏2022-12-23 17.50.19.png

服务端组件的优势是什么?

  • 可以使用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 标签了。
  • 官方文档